深度反应useEffect / useEffect的使用?
Posted
技术标签:
【中文标题】深度反应useEffect / useEffect的使用?【英文标题】:React useEffect in depth / use of useEffect? 【发布时间】:2020-05-07 13:19:48 【问题描述】:我正在尝试深入了解useEffect
钩子。
我想知道什么时候使用哪种方法以及为什么?
1.useEffect with no second paraments
useEffect(()=>)
2.useEffect with second paraments as []
useEffect(()=>,[])
3.useEffect with some arguments passed in the second parameter
useEffect(()=>,[arg])
【问题讨论】:
1.在挂载和每个依赖项更新(任何状态/道具更改)时都被调用。 2. 仅在挂载时调用,因为您指定了空的依赖项列表。 3. 在挂载和更改任何列出的依赖项时调用 Dan Abramov 写了一篇关于 useEffect 的优秀博文:overreacted.io/a-complete-guide-to-useeffect。你应该阅读它;-) 【参考方案1】:useEffect(callback);
// Example
useEffect(() =>
console.log("executed after render phase");
return () =>
console.log("cleanup function after render");
;
);
在每个组件渲染上运行。
通常用于调试,类似于每个函数的主体执行
渲染:
const Component = () =>
callback()
return <></>;
;
cleanup function 在每次渲染后运行。注意:在执行时间上仍然存在差异(请参阅下一个注释)。 Check this sandbox logs.
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之后执行。由于closures 导致数据过时请记住,有一个先渲染和然后一个坐骑。
粗略地说,大多数关于
useEffect
的错误是不知道闭包是如何工作的,并且没有注意 linting 警告。
确保数组包含组件范围中的所有值,这些值随时间变化并被效果器使用。否则,您的代码将引用以前渲染中的陈旧值 - note in React docs。
useEffect(callback,[arg]);
// Example
useEffect(() =>
console.log( users );
return () =>
console.log("user value is changing");
;
, [users]);
在arg
值更改时运行。
通常用于在道具/状态更改时运行事件。
可以提供多个依赖:[arg1,arg2,arg3...]
清理功能在arg
值更改时运行。
陷阱:
“On Change”指的是shallow comparison,之前的值为arg
。
即比较上一次渲染中
arg
的值和当前渲染prevArg === arg ? doNothing() : callback()
的值。
因为在 javascript 中 === || [] === []
是一个falsy 语句,如果arg
(在我们的示例中为users
)是一个对象,则回调将在每次渲染时运行。
也可以在 mount 上运行,因为第一次比较总是错误的
其他必知事项
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
as useEffect
'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 文档
【讨论】:
请注意,缺少依赖项可能会导致 stale closures。以下代码:const [s, setS] = useState(0); useEffect(() => setInterval(() => console.log(s), 1), []);
只会记录 0,因为回调在 s 结束时关闭,即使在每次渲染时重新创建该函数,它也只会在挂载时调用,并且时间 s 为 0。看到问题弹出很多次与此错误和异步状态设置有关,但对于功能组件,其根本原因是陈旧的闭包。
run on every render
我会把它改成runs after each render
和清理功能runs before each unmount, either the final unmount or before the next render attempt
“在每次卸载之前运行,无论是最终卸载还是在下一次渲染尝试之前”它的声音就像有一个“卸载尝试”,但没有这样的。
您希望将其中一个答案放入框架中并每周阅读【参考方案2】:
如果你熟悉 React 类生命周期方法,可以将 useEffect Hook 视为 componentDidMount、componentDidUpdate 和 componentWillUnmount 的组合。
1.useEffect 没有第二个参数:当我们希望在组件刚刚挂载或已更新时发生某些事情时使用它。从概念上讲,我们希望它在每次渲染之后发生。
2.useEffect with second paraments as [] : 当我们希望在安装组件时发生某些事情时使用,如果在安装时只执行一次。它更接近熟悉的 componentDidMount 和 componentWillUnmount .
3.useEffect 在第二个参数中传递一些参数:当我们希望在参数传递时发生某些事情时使用它,例如。 args 在您的情况下发生了变化。
了解更多信息。在这里查看:https://reactjs.org/docs/hooks-effect.html
【讨论】:
以上是关于深度反应useEffect / useEffect的使用?的主要内容,如果未能解决你的问题,请参考以下文章