深度反应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 <></>;
;

注意:在执行时间上仍然存在差异(请参阅下一个注释)。 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之后执行。

请记住,有一个先渲染然后一个坐骑。

由于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? 有时您需要在装载或首次渲染时运行useEffectONCE,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(() =&gt; setInterval(() =&gt; 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的使用?的主要内容,如果未能解决你的问题,请参考以下文章

反应 useEffect 比较对象

反应 useEffect 和 setInterval

在函数内反应 useEffect 陈旧值

在useEffect中反应丢失变量?

基本反应问题。为啥在 React 文档的这个例子中需要 useEffect ?

如何在useEffect中使用axios请求测试反应组件?