preface
The basic uses of React Hooks are already well documented. The purpose of this article is to analyze in detail some puzzling problems and the reasons behind them through a simple example. This is the second in a series on useEffect.
Personal Blog address🍹 🍰 fe – code
Class lifecycle
According to the official documentation, useEffect’s callbacks and mechanism for cleaning up side effects can be likened to the life cycle in a class component. However, this analogy is also confusing because of the different nature of the class component and the function component.
If you’re familiar with React class lifecycle functions, you can think of useEffect Hook as a combination of componentDidMount, componentDidUpdate, and componentWillUnmount. — Use Effect Hook
But sometimes things can go wrong, as in our initial timer example.
function Counter() {
const [count, setCount] = useState(0);
useEffect(() = > {
const id = setInterval(() = > {
setCount(count + 1);
}, 1000); } []);return <h1>{count}</h1>;
}
Copy the code
Our requirement is to set a timer when componentDidMount. And ensure that not every update (componentDidUpdate) are reset. So we set the second parameter to [] to achieve the same effect.
This is problematic, of course, because because of the way functional components are executed, the count we get in useEffect is a reference to the closure, and each update is a whole new execution context. This was analyzed in detail in the previous article. But in the class component, the reference in the lifecycle is this.state.count, and unlike the function, the count is up to date each time.
React Hooks also provide a hook that works like this to help us save values – useRef, which can easily hold any variable value, similar to the way we use instance fields in a class. But it doesn’t really apply here.
In general, useEffect is different from the real life cycle, and should be used with more attention.
Rely on
From the first article, we learned some important things, such as that each update is a rerun. This is not just for useState, but for the entire function component. If you don’t know much about it, read the React hooks — useState section.
function Counter() {
const [count, setCount] = useState(0);
useEffect(() = > {
const id = setInterval(() = > {
setCount(count + 1);
}, 1000); } []);return <h1>{count}</h1>;
}
Copy the code
We know that each update is a rerun. The second argument we pass to useEffect is [], so we can have the effect that the callback will only run once (set the timer only once).
However, it is important to know that just because the callback function is only run once does not mean that useEffect is only run once. In each update, useEffect is still executed each time, but because the array dependencies passed to it are empty, React checks each time and doesn’t notice the dependency change, so it doesn’t reexecute the callback.
Checking dependencies is simply a matter of comparing values or references for equality.
And the above writing, the official is not recommended. We should make sure that all the states used in useEffect, such as count, are fully added to the dependency array. It doesn’t matter if the reference is a value of the underlying type, an object or even a function.
function Counter() {
const [count, setCount] = useState(0);
useEffect(() = > {
const id = setInterval(() = > {
setCount(count + 1);
SetCount (count => count + 1);
}, 1000);
}, [count]); // Make sure all state dependencies are here
console.log(count);
return <h1>{count}</h1>;
}
Copy the code
This will ensure that you get the current count value every time in the callback.
Side effects
Yi! There seems to be something strange.
What terrible thing has happened??
Now think about what we’ve done.
- There’s a timer in the useEffect callback.
- The dependency array writes the count as required.
- Each update caused by a change in count also runs a callback to useEffect.
- The timer in the callback is also reset.
- Yeah, I think I found a problem.
With each update, the useEffect callback is re-run, which resets a timer. One problem is that the last timer we set hasn’t been cleaned up, so frequent updates cause more and more timers to be running at the same time. To solve this problem, you need to use another feature of useEffect: removing side effects.
function Counter() {
const [count, setCount] = useState(0);
useEffect(() = > {
const id = setInterval(() = > {
setCount(count + 1);
}, 1000);
// Return a function to clean up side effects
return () = > {
clearInterval(id);
}
}, [count]);
console.log(count);
return <h1>{count}</h1>;
}
Copy the code
Ok, the world is quiet.
So, think again. When does useEffect clean up side effects? Before the next view update?
function Counter() {
const [count, setCount] = useState(0);
useEffect(() = > {
const id = setInterval(() = > {
console.log(1.'I am the timer', count);
setCount(count + 1);
}, 1000);
return () = > {
console.log(2.'What I clean up is${count}Side effects');
clearInterval(id);
}
}, [count]);
console.log(3.'I'm rendering', count);
return <h1>{count}</h1>;
}
Copy the code
Would the above code be printed in order 1, 2, 3?
Obviously not, useEffect cleans up the last side effect after the view has been updated. This treatment is in fact consistent with the useEffect characteristics. React only runs useEffect after the browser is drawn. So the removal of Effect is also delayed. The previous Effect will be cleared after re-rendering.
summary
When using useEffect, you need to be careful about referencing states, adding dependencies, and removing side effects (without them, you don’t need them). In many cases, other hooks are needed to complete this work, such as useRef/useCallback, etc.
Refer to the article
- UseEffect complete guide
- Use Effect Hook
Communication group
Wechat group: scan code reply and add group.
Afterword.
If you’re reading this, and this has helped you a little bit, I hope you can give the author a hand, thanks 🍻. If there are any errors in the text, we are also welcome to point out, encourage. Well, thanks again for your time, thanks for reading, and see you next time!
- The article warehouse 🍹 🍰 fe – code
Interested students can pay attention to my public number front-end engine, fun and material.