The hooks introduced with React 16.8 are a nice way to control state and other features on functional React components. They discard the necessity of third-party libraries such as Recompose – which is the inspiration for React hooks, by the way.
One way one can apply the useEffect
hook, for example, is to mimic the behavior of componentDidMount
event to bind a value returned by an asynchronous function to a given state. Like:
const React, { useEffect, useState } from 'react'; export default Component = () => { const [ data, setData ] = useState(null); useEffect(() => { (async () { setData(await someAsyncApiCall()); })(); }, []); return (<span>{ data }</span>);
Calling the useEffect
hook with an empty array will make it be called only when the component was mounted, i.e. is the same as componentDidMount
event.
However, if the component has unmounted some point before the async call finishes, it’s likely to get the following error in the console:
Can’t perform a React state update on an unmounted component
That happens because the async function called setData
, which is the state setter, after the component has unmounted. To fix that error, it’s required to cancel the async function before changing the state in case the component did unmount.
In a “regular” React component, there is the componentWillUnmount
event. One could set a flag to indicate the component is not mounted anymore to avoid setting the state late. Simulating this same approach with hooks is not hard. A function returned by a useEffect
hook with an empty array in the second argument (the case above) run when the component will unmount. So, one could have the following:
const React, { useEffect, useState } from 'react'; export default Component = () => { const [ data, setData ] = useState(null); useEffect(() => { let mounted = true; // Indicate the mount state (async () { const data = await someAsyncApiCall(); if (!mounted) return; // Exits if comp. is not mounted setData(data); })(); return () => { // Runs when component will unmount mounted = false; }; }, []); return (<span>{ data }</span>);
Now the error is gone since the state is not updated if the component is not mounted anymore.
I particularly am fond of hooks. I used to add Recompose to projects in the past and like the way the code looks with functional components. There is also, the performance benefits.
If you have questions or suggestions, feel free to express yourself in the comments below.