React useEffect Hook
In my last posts we introduced the React Hooks and talked a little about managing the state with the state hooks (useState
and useReducer
). In this post we’ll cover the Effect Hook useEffect
.
The Effect Hook lets you perform side effects in function components. Some examples of “side effects” or just “effects” can be data fetching, manually changing the DOM or setting up a subscription.
With the useEffect
Hook we can tell React that after every render, the callback passed to this useEffect
function as its first parameter (“effect”) should be called. React will remember this callback and call it later after performing the DOM updates.
useEffect(() => {
// Here the effect
});
Below is an example of an app with an input that changes the document title using Hooks:
Before Hooks, we only could manage this effects within the lifecycle methods of class components: componentDidMount
, componentDidUpdate
and componentWillUnmount
. The logic of an effect ended up being spread out throughout the different lifecycle methods.
The example of the previous app implemented without Hooks:
We could extract the logic of updating the document title from the component state, but still we’ll have to call the updater function from different lifecycle methods.
When does useEffect run?
By default, it runs after every render but we can customize it with the second param of the useEffect
function. As a second argument, the useEffect
function accepts an array that allow us to tell React when we want our effect to be called.
After a render and before calling an effect, React will compare the array of values defined in the second parameter of the effect with the array defined in the same effect from the previous render. React will only call the effect when any value of the array has changed since the previous render.
In the previous example, we don’t need to update the document title (our effect) after every render but only when the state variable name
has changed its value since the previous render. That’s why we pass an array with the value of name
as the second parameter:
The same way, if we only want our effect to be called only after the first render, we have to pass an empty array []
(which never changes) as second parameter.
How do effects run?
Unlike componentDidMount
and componentDidUpdate
, effects scheduled with useEffect
don’t block the browser from updating the screen. If you need your effect to be happen synchronously, you can use the Hook useLayoutEffect
which has the same API as useEffect
.
Effects with cleanup
There are some effects that require a cleanup to avoid memory leaks like subscriptions to external sources.
This is how we do the subscription of a component to an external source without Hooks:
And below the same example using Hooks:
As long as we only want our effect (subscribe to resizes) to be called once, we pass an empty array as the second parameter of the function useEffect
.
An effect can optionally return a function (the cleanup function) that React will call when the component unmounts and before running the effect next time. In the example, our effect returns a function that unsubscribes it from the window resize events.
Example with multiple effects
It’s always a good idea to use multiple effects to separate concerns. Below is an example of a component that is subscribed to window resizes (we do this with the first effect) and shows the type of screen we’re managing depending on its width (second effect).
Summing up
React useEffect
Hook allows you to manage side effects with no need of class components, and to extract and reuse the logic of an effect from a component. Before using it, it’s important to know the key points we covered in this post:
- When and how does React perform the effects.
- How to customize when an effect should be called.
- How to cleanup the effects when unmounting the component.