我正在尝试深入了解 useEffect
Hook 。
我想知道何时使用哪种方法以及为什么?
- useEffect 不带第二个参数
useEffect(()=>{})
- useEffect,第二个参数为
[]
useEffect(()=>{},[])
- useEffect 在第二个参数中传递了一些参数
useEffect(()=>{},[arg])
最佳答案
useEffect(callback);
// Example
useEffect(() => {
console.log("executed after render phase");
return () => {
console.log("cleanup function after render");
};
});
- 在每个组件渲染上运行。
- 通常用于调试,类似于每个函数的函数体执行 渲染:
const Component = () => {
callback()
return <></>;
};
Note: There is still a difference, in execution time (see the next note). Check this sandbox logs.
- cleanup function每次渲染后运行。
useEffect(callback,[]);
// Example
useEffect(() => {
const fetchUsers = async () => {
const users = await fetch();
setUsers(users);
};
fetchUsers();
console.log("called on component's mount");
return () => {
console.log("called on component's unmount");
};
}, []);
- 通常用于通过数据获取等方式初始化组件状态。
- 在组件安装上运行一次。
- cleanup function将在组件卸载时运行。
陷阱:
- 在 render phase 之后执行回调.
Remember, there is a first render and then a mount.
- 由于 closures 导致数据过时
Roughly saying, most of bugs regarding
useEffect
is not knowing how closures works and not paying attention to linting warnings.
<小时/>Make sure the array includes all values from the component scope that change over time and that are used by the effect. Otherwise, your code will reference stale values from previous renders - note in React docs.
useEffect(callback,[arg]);
// Example
useEffect(() => {
console.log({ users });
return () => {
console.log("user value is changing");
};
}, [users]);
- 在
arg
值发生变化时运行。 - 通常用于在 Prop /状态更改时运行事件。
- 可以提供多个依赖项:
[arg1,arg2,arg3...]
- 清理函数在
arg
值更改时运行。
陷阱:
- “On Change”指的是 shallow comparison 与
arg
的先前值。
i.e compares the value of
arg
from the previous render and the current one,prevArg === arg ? doNothing() : callback()
.
因为在 Javascript
{} === {} || [] === []
是一个 falsy 语句,如果arg
(在我们的示例中是users
)是一个对象,则回调将在每次渲染时运行。也在挂载上运行,因为第一次比较总是错误的
其他值得注意的要点
useEffect
回调 fired after browser's re-paint .useEffect
回调按声明顺序执行 ( like all hooks ),检查 example .- 每个
useEffect
都应该有一个 SINGLE responsibility . - 如果您使用
useRef
中的值,请在清理函数中预先将该值复制到回调的作用域。
const timeoutIdRef = useRef();
useEffect(() => {
const timeoutId = timeoutIdRef.current;
return () => {
/*
Using timeoutIdRef.current directly here is not safe
since you can't guarantee the ref to exists in this point
(especially when the component unmounts)
*/
// Should get a lint warning here
clearTimeout(timeoutIdRef.current); // BAD
// Closure on timeoutId value
clearTimeout(timeoutId); // GOOD
};
}, [arg]);
- Is it safe to use
ref.current
asuseEffect
's dependency when ref points to a DOM element? - 有时您需要在安装或首次渲染时运行
useEffect
ONCE,those are the common patterns .
const isMounted = useRef(false);
useEffect(() => {
if (isMounted.current) {
// first mount
} else {
isMounted.current = true;
}
}, [arg]);
<小时/>
继续阅读:
- 我的additional answer解释
useEffect
回调的return
语句 - A Complete Guide to
useEffect
by Dan Abramov -
useEffect
API - Using the effect hook - react 文档
关于javascript - 深入React useEffect/useEffect的使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59841800/