How can the useEffect
hook (or any other hook for that matter) be used to replicate componentWillUnmount
?
In a traditional class component I would do something like this:
class Effect extends React.PureComponent { componentDidMount() { console.log("MOUNT", this.props); } componentWillUnmount() { console.log("UNMOUNT", this.props); } render() { return null; } }
With the useEffect
hook:
function Effect(props) { React.useEffect(() => { console.log("MOUNT", props); return () => console.log("UNMOUNT", props) }, []); return null; }
(Full example: https://codesandbox.io/s/2oo7zqzx1n)
This does not work, since the "cleanup" function returned in useEffect
captures the props as they were during mount and not state of the props during unmount.
How could I get the latest version of the props in useEffect
clean up without running the function body (or cleanup) on every prop change?
A similar question does not address the part of having access to the latest props.
The react docs state:
If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run.
In this case however I depend on the props... but only for the cleanup part...
Using componentWillUnmount with useEffectuseEffect(() => { window. addEventListener("mousemove", () => {}); return () => { window. removeEventListener("mousemove", () => {}) } }, []); That's it.
Either way, we're now safe to use async functions inside useEffect hooks. Now if/when you want to return a cleanup function, it will get called and we also keep useEffect nice and clean and free from race conditions. Enjoy using async functions with React's useEffect from here on out!
useEffect runs on every render, it is a combination of componentDidUpdate, componentDidMount and ComponentWillUnmount. If we add an empty array in useEffect it runs just when the component mounted. It is because useEffect will compare the array you passed to it.
We should see 5 “Use Effects” logged to the console, one when the component is first rendered, the one for each button click, meaning that the useEffect doesn't currently run on unmount.
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]);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With