React has a built-in hook called useEffect. Hooks are used in function components. The Class
component comparison to useEffect
are the methods componentDidMount
, componentDidUpdate
, and componentWillUnmount
.
useEffect
will run when the component renders, which might be more times than you think. I feel like I’ve had this come up a dozen times in the past few weeks, so it seems worthy of a quick blog post.
import React, { useEffect } from 'react';
function App() {
useEffect(() => {
// Run! Like go get some data from an API.
});
return (
<div>
{/* Do something with data. */}
</div>
);
}
In a totally isolated example like that, it’s likely the useEffect
will run only once. But in a more complex app with props flying around and such, it’s certainly not guaranteed. The problem with that is that if you’re doing something like fetching data from an API, you might end up double-fetching which is inefficient and unnecessary.
useEffect
takes a second parameter.
The trick is that The second param is an array of variables that the component will check to make sure changed before re-rendering. You could put whatever bits of props and state you want in here to check against.
Or, put nothing:
import React, { useEffect } from 'react';
function App() {
useEffect(() => {
// Run! Like go get some data from an API.
}, []);
return (
<div>
{/* Do something with data. */}
</div>
);
}
That will ensure the useEffect
only runs once.
Note from the docs:
If you use this optimization, make sure the array includes all values from the component scope (such as props and state) that change over time and that are used by the effect. Otherwise, your code will reference stale values from previous renders.
Or simply use eslint-plugin-react-hooks to be sure about your hooks and how you’re using them!
https://www.npmjs.com/package/eslint-plugin-react-hooks
That looks useful but I don’t think it solves the problem.
This is absolutely correct, but can be dangerous when misunderstood and misused/overused.
There’s an amazing (but long) explanation of all the ins and outs of useEffect written by Dan Abramov which really crystalized it for me.
https://overreacted.io/a-complete-guide-to-useeffect/
Two things, by design, React will render when props or state changes. Since
useEffect
runs each and every time, you are bound to fall into an infinite loop if you change the state or props in it. Also, to getcomponentDidMount
, you run some code then you pass an empty array as the second parameter touseEffect
. To runcomponentWillUnmount
just once, you return a cleanup function fromuseEffect
and pass an empty array as the second parameter too.I’ve been converting some of my codebases to Hooks, and it’s getting pretty fascinating. One thing with
useEffect
is that it’s easy to mess it up – and I already did quite a number of times. But apart from that, it solves a lot of problems and as a bonus, it does it simply.The issue with this approach is that it will fire a warning if you depend on any props or state (due to the
react-hooks/exhaustive-deps
eslint rule).Better define a custom Hook in your codebase:
And import it and use it.