Accessing React state in your component cleanup with hooks
Today I came across an interesting problem where I needed to access a piece of React state when unmounting a component, a problem that would have been trivial with Class components and componentWillUnmount
, however with hooks, the solution was less clear.
If you’re just looking for the solution here it is; I will be diving into it below to try and understand it a bit better.
const [value, setValue] = useState();
const valueRef = useRef();
useEffect(() => {
valueRef.current = value;
}, [value]);
useEffect(() => {
return function cleanup() {
console.log(valueRef.current);
};
}, []);
useEffect
The useEffect
hook allows you to perform side-effects in your components when something happens, for instance when the component is first rendered, when a property or piece of state is updated, or when the component is about to be unmounted.
The useEffect
hook is defined as follows:
useEffect(effectFunction: React.EffectCallback, dependencies?: React.DependencyList | undefined)
// for example
useEffect(() => {
console.log(value);
}, [value]);
In this example, the value
will be output to the console every time it changes including when it is initialised.
The dependency list passed into useEffect
is particularly interesting; whenever one of the variables in that array changes, the effect function will be run. If we omit the dependency list, the function will run both after the first render and after every update. If we instead pass in an empty dependency list, the function will only be run when the component is initialised.
We can also return a function from useEffect
that can cleanup any side effects, for instance, we may want to unsubscribe from an external data source to prevent possible memory leaks. If we choose to include some variables in our dependency array or omit it entirely, the cleanup function will be run on each update to clean up effects from the previous render as well as when the component unmounts.
If we only want to run the cleanup function when the component unmounts, we set the dependency array to []
.
Our solution makes use of 2 useEffect
statements, one to output the value
to the console only when the component is to be unmounted and the other to update the valueRef
with the current value
.
useRef
The useRef
hook creates a ref
which has 2 main use cases, to access a child component outside of the usual props
flow or to store a mutable value that exists for the lifetime of the component. In our case, we use the latter.
A ref
is a generic container that can store a value using its current
property similar to using instance variables in object oriented programming. It is different from state since it does not cause a rerender when it is updated.
Since the ref
is mutable and exists for the lifetime of the component, we can use it to store the current value
whenever it is updated and still access that value
in the cleanup function of our useEffect
via the valueRef
.