There are a couple of things there. First, to fix the code, you could update your useEffect to this:
useEffect(() => {
messagesRef.on('child added', snapshot => {
const message = snapshot.val();
message.key = snapshot.key;
setMessages(messages.concat(message)); // See Note 1
}, []); // See Note 2
Note 1
The setMessages line is how you update your state. useState is a little bit different from the "old" setState in a sense that will completely replace the state value. React documentation says:
This is because when we update a state variable, we replace its value. This is different from this.setState in a class, which merges the updated fields into the object.
Note 2
React Hooks changes the way we build apps and it is not a real "translation" from the old lifecycles.
The empty brackets ([]) in the last line, will make your code "similar" to componentDidMount, but most importantly, will make your effect run only once.
Dan Abramov said (removed some of the original text):
While you can useEffect(fn, []), it’s not an exact equivalent. Unlike componentDidMount, it will capture props and state. So even inside the callbacks, you’ll see the initial props and state. (...) Keep in mind that the mental model for effects is different from componentDidMount and other lifecycles, and trying to find their exact equivalents may confuse you more than help. To get productive, you need to “think in effects”, and their mental model is closer to implementing synchronization than to responding to lifecycle events.
Full article about useEffect here.
Answer from Bruno Monteiro on Stack OverflowThere are a couple of things there. First, to fix the code, you could update your useEffect to this:
useEffect(() => {
messagesRef.on('child added', snapshot => {
const message = snapshot.val();
message.key = snapshot.key;
setMessages(messages.concat(message)); // See Note 1
}, []); // See Note 2
Note 1
The setMessages line is how you update your state. useState is a little bit different from the "old" setState in a sense that will completely replace the state value. React documentation says:
This is because when we update a state variable, we replace its value. This is different from this.setState in a class, which merges the updated fields into the object.
Note 2
React Hooks changes the way we build apps and it is not a real "translation" from the old lifecycles.
The empty brackets ([]) in the last line, will make your code "similar" to componentDidMount, but most importantly, will make your effect run only once.
Dan Abramov said (removed some of the original text):
While you can useEffect(fn, []), it’s not an exact equivalent. Unlike componentDidMount, it will capture props and state. So even inside the callbacks, you’ll see the initial props and state. (...) Keep in mind that the mental model for effects is different from componentDidMount and other lifecycles, and trying to find their exact equivalents may confuse you more than help. To get productive, you need to “think in effects”, and their mental model is closer to implementing synchronization than to responding to lifecycle events.
Full article about useEffect here.
You tried to declare the state again instead of using the state updater
useEffect(() => {
messagesRef.on('child added', snapshot => {
const message = snapshot.val();
message.key = snapshot.key;
// setMessages is the state updater for messages
// instead of an object with messages: messagesArray
// just save it as an array the name is already messages
setMessages([...messages, message]);
});
// useEffect takes an array as second argument with the dependencies
// of the effect, if one of the dependencies changes the effect will rerun
// provide an empty array if you want to run this effect only on mount
}, []);
Videos
we know that componentDidMount will be called once the page is mounted, but we cant call this function once again. is the case same in useEffect?
For the stable version of hooks (React Version 16.8.0+)
For componentDidMount
useEffect(() => {
// Your code here
}, []);
For componentDidUpdate
useEffect(() => {
// Your code here
}, [yourDependency]);
For componentWillUnmount
useEffect(() => {
// componentWillUnmount
return () => {
// Your code here
}
}, [yourDependency]);
So in this situation, you need to pass your dependency into this array. Let's assume you have a state like this
const [count, setCount] = useState(0);
And whenever count increases you want to re-render your function component. Then your useEffect should look like this
useEffect(() => {
// <div>{count}</div>
}, [count]);
This way whenever your count updates your component will re-render. Hopefully this will help a bit.
There is no exact equivalent for componentDidMount in react hooks.
In my experience, react hooks requires a different mindset when developing it and generally speaking you should not compare it to the class methods like componentDidMount.
With that said, there are ways in which you can use hooks to produce a similar effect to componentDidMount.
Solution 1:
useEffect(() => {
console.log("I have been mounted")
}, [])
Solution 2:
const num = 5
useEffect(() => {
console.log("I will only run if my deps change: ", num)
}, [num])
Solution 3 (With function):
useEffect(() => {
const someFunc = () => {
console.log("Function being run after/on mount")
}
someFunc()
}, [])
Solution 4 (useCallback):
const msg = "some message"
const myFunc = useCallback(() => {
console.log(msg)
}, [msg])
useEffect(() => {
myFunc()
}, [myFunc])
Solution 5 (Getting creative):
export default function useDidMountHook(callback) {
const didMount = useRef(null)
useEffect(() => {
if (callback && !didMount.current) {
didMount.current = true
callback()
}
})
}
It is worth noting that solution 5 should only really be used if none of the other solutions work for your use case. If you do decide you need solution 5 then I recommend using this pre-made hook use-did-mount.
Source (With more detail): Using componentDidMount in react hooks
You need to add a dependency array for it to know when to recall this hook. An empty dep array will only call it once aka "on mount". And if you don't provide a dep array then it will just be called on every re-render.
useEffect(() => {
MapboxGL.setTelemetryEnabled(false);
}, []);
You can create a flag and if the flag is false/true then only perform that action. something as simple as this
useEffect(() => {
if (something) {
MapboxGL.setTelemetryEnabled(false);
setSomething(false)
}
});
or if you only need hook once, you can do what Matt have suggested
useEffect(() => {
MapboxGL.setTelemetryEnabled(false);
}, []);