You cannot use any of the existing lifecycle methods (componentDidMount, componentDidUpdate, componentWillUnmount etc.) in a hook. They can only be used in class components. And with Hooks you can only use in functional components. The line below comes from the React doc:
If you’re familiar with React class lifecycle methods, you can think of
useEffectHook ascomponentDidMount,componentDidUpdate, andcomponentWillUnmountcombined.
suggest is, you can mimic these lifecycle method from class component in a functional components.
Code inside componentDidMount run once when the component is mounted. useEffect hook equivalent for this behaviour is
useEffect(() => {
// Your code here
}, []);
Notice the second parameter here (empty array). This will run only once.
Without the second parameter the useEffect hook will be called on every render of the component which can be dangerous.
useEffect(() => {
// Your code here
});
componentWillUnmount is use for cleanup (like removing event listeners, cancel the timer etc). Say you are adding a event listener in componentDidMount and removing it in componentWillUnmount as below.
const mouseMoveHandler = () => {}
componentDidMount() {
window.addEventListener('mousemove', mouseMoveHandler)
}
componentWillUnmount() {
window.removeEventListener('mousemove', mouseMoveHandler)
}
Hook equivalent of above code will be as follows:
useEffect(() => {
const mouseMoveHandler = () => {}
window.addEventListener('mousemove', mouseMoveHandler);
// returned function will be called on component unmount
return () => {
window.removeEventListener('mousemove', mouseMoveHandler)
}
}, [])
Answer from Bhaskar Gyan Vardhan on Stack OverflowYou cannot use any of the existing lifecycle methods (componentDidMount, componentDidUpdate, componentWillUnmount etc.) in a hook. They can only be used in class components. And with Hooks you can only use in functional components. The line below comes from the React doc:
If you’re familiar with React class lifecycle methods, you can think of
useEffectHook ascomponentDidMount,componentDidUpdate, andcomponentWillUnmountcombined.
suggest is, you can mimic these lifecycle method from class component in a functional components.
Code inside componentDidMount run once when the component is mounted. useEffect hook equivalent for this behaviour is
useEffect(() => {
// Your code here
}, []);
Notice the second parameter here (empty array). This will run only once.
Without the second parameter the useEffect hook will be called on every render of the component which can be dangerous.
useEffect(() => {
// Your code here
});
componentWillUnmount is use for cleanup (like removing event listeners, cancel the timer etc). Say you are adding a event listener in componentDidMount and removing it in componentWillUnmount as below.
const mouseMoveHandler = () => {}
componentDidMount() {
window.addEventListener('mousemove', mouseMoveHandler)
}
componentWillUnmount() {
window.removeEventListener('mousemove', mouseMoveHandler)
}
Hook equivalent of above code will be as follows:
useEffect(() => {
const mouseMoveHandler = () => {}
window.addEventListener('mousemove', mouseMoveHandler);
// returned function will be called on component unmount
return () => {
window.removeEventListener('mousemove', mouseMoveHandler)
}
}, [])
useComponentWillMount hook
const useComponentWillMount = (cb) => {
const willMount = useRef(true)
if (willMount.current) cb()
willMount.current = false
}
This hook could be a saver when there is an issue of sequence (such as running before another script). If that isn't the case, use useComnponentDidMount which is more aligned with React hooks paradigm.
useComponentDidMount hook
const useComponentDidMount = cb => useEffect(cb, []);
If you know your effect should only run once at the beginning use this solution. It will run only once after component has mounted.
useEffect paradigm
Class components have lifecycle methods which are defined as points in the timeline of the component. Hooks don't follow this paradigm. Instead effects should be structured by their content.
function Post({postID}){
const [post, setPost] = useState({})
useEffect(()=>{
fetchPosts(postID).then(
(postObject) => setPost(postObject)
)
}, [postID])
...
}
In the example above the effect deals with fetching the content of a post. Instead of a certain point in time it has a value it is dependent on - postID. Every time postID gets a new value (including initialization) it will rerun.
Component Will Mount discussion
In class components componentWillMount is considered legacy (source 1, source2). It's legacy since it might run more than once, and there is an alternative - using the constructor. Those considerations aren't relevant for a functional component.
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.
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
}, []);
componentWillUnmount with React useEffect hook
useEffect as componentWillUnmount - javascript
Does useEffect completely replace mounting lifecycle ?
is useEffect a replacement for componentDidMount ?
Videos
You can make use of useRef and store the props to be used within a closure such as render useEffect return callback method
function Home(props) {
const val = React.useRef();
React.useEffect(
() => {
val.current = props;
},
[props]
);
React.useEffect(() => {
return () => {
console.log(props, val.current);
};
}, []);
return <div>Home</div>;
}
DEMO
However a better way is to pass on the second argument to useEffect so that the cleanup and initialisation happens on any change of desired props
React.useEffect(() => {
return () => {
console.log(props.current);
};
}, [props.current]);
useLayoutEffect() is your answer in 2021
useLayoutEffect(() => {
return () => {
// Your code here.
}
}, [])
This is equivalent to ComponentWillUnmount.
99% of the time you want to use useEffect, but if you want to perform any actions before unmounting the DOM then you can use the code I provided.
React doesn't remember isDropdownMounted variable. It will be recreated on each render. It will be better to use useRef hook to set value in useEffect and remember it on the next render.
const isDropdownMounted = useRef(null);
useEffect(() => {
isDropdownMounted.current = true;
return function cleanup() {
isDropdownMounted.current = false;
};
}, []);
useEffect lets you return a cleanup function that will run whenever your component unmounts.
NOTE: It will also run whenever something in the dependency array of the useEffect changes. It assures you that you'll always get a "fresh" effect.
React docs on useEffect with cleanup.
Here is the example they use:
Using classes:
componentDidMount() {
ChatAPI.subscribeToFriendStatus(
this.props.friend.id,
this.handleStatusChange
);
}
componentWillUnmount() {
ChatAPI.unsubscribeFromFriendStatus(
this.props.friend.id,
this.handleStatusChange
);
}
Using hooks:
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
// Specify how to clean up after this effect:
return function cleanup() {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
Here is a working example:
function App() {
const [boolean,setBoolean] = React.useState(true);
const toggleBoolean = () => setBoolean((prevState) => !prevState);
return(
<div>
{ boolean ?
<Component1/>
: <Component2/>
}
<button onClick={toggleBoolean}>Toggle</button>
</div>
);
}
function Component1() {
React.useEffect(() => {
console.log("Component1 has mounted...");
return () => { console.log("Component1 has unmounted...")};
},[]);
return(
<div>Component1</div>
);
}
function Component2() {
return(
<div>Component2</div>
);
}
ReactDOM.render(<App/>, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
Hi, I'm wondering if useEffect replaces the lifecycle while using componentDidMount(), componentWillMount(), etc. Are they worth learning?
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?