React useEffect 清理函数中的依赖没有更新

Posted

技术标签:

【中文标题】React useEffect 清理函数中的依赖没有更新【英文标题】:Dependencies in React useEffect cleanup function are not updated 【发布时间】:2021-08-20 11:09:04 【问题描述】:

我在尝试使用 useEffect 在卸载组件时调用清理函数时遇到了一个奇怪的问题。

在我的 useEffect 返回中,我调用了一个 useCallback 函数,其中正确添加了依赖项。在那里检查名为status 的状态变量,但该变量永远不会从初始状态更新。我无法将变量传递给 useEffect,因为我只想在组件因特定原因卸载时触发它。 我在 codepen here 中重新创建了一个简化版本,但我无法理解这一点。也许有人知道为什么会这样? 谢谢! (这只是最近才开始发生的,它以前工作过,所以我更加困惑!)

【问题讨论】:

【参考方案1】:

感谢您的回答。 所以,我终于知道发生了什么。 useEffect 创建一个闭包,并且函数在该闭包中,这意味着作为字符串的状态与第一次渲染一样(创建闭包时)保持不变,并且永远不会更新。 正如@ilkerkaran 所提到的,一种方法是使用useRef,但这是因为它创建了一个对象,这意味着 ref.current 属性具有到原始对象的链接并且它始终保持同步。 另一种方法是执行 useMemo 并返回一个具有 status 属性的对象,这实际上是 useRef 在引擎盖下。 所以实际上,如果 state 是一个对象,并且我们将 state 作为依赖项传递,则 stayus 属性将出于同样的原因按预期工作。我希望这对其他人也有帮助并节省一些时间

【讨论】:

谢谢。 useRef 是迄今为止我见过的最好的解决方案。【参考方案2】:

实际上,您的代码并非如此。回调函数根据依赖数组更新。您可以通过在 useEffect 上方调用 remove() 来看到这一点。这样,函数将在每次渲染时执行。

在您的示例中发生了什么;

它呈现,(通过第一次按下切换按钮) 然后在 useEffect 中调用setStatus("mounted") 触发第二次渲染(通过第二次按下切换按钮) 然后它会在上次卸载时渲染 默认状态值

最后一部分实际上也让我感到烦恼。您可以通过在 useEffect 定义上方放置一个简单的 console.log 来观察此行为。

您也可以通过使用 useRef 而不是 useState 来解决此问题

【讨论】:

【参考方案3】:

原因是你的useEffect

 React.useEffect(() => 
    setStatus("mounted")
    return () => remove()
  , []) 

你有一个 useEffect 的依赖项设置为 []。这意味着您的 useEffect 将只运行一次。因此,这就是您的组件从上到下执行流程的方式,因此您创建了一个删除函数,此时您的初始状态为 not mounted 。现在你的dom被画了。你 useEffect 被调用你设置状态现在你得到一个全新的删除功能。现在您卸载组件,清理将使用 第一次渲染中的 remove 函数。

为了让您的状态反映在 remove 中,您需要在 useEffect 中添加 status 作为依赖项。

 React.useEffect(() => 
    setStatus("mounted")
    return () => remove()
  , [status]) 

【讨论】:

以上是关于React useEffect 清理函数中的依赖没有更新的主要内容,如果未能解决你的问题,请参考以下文章

react 钩子中的 useEffect 执行顺序及其内部清理逻辑是啥?

React+Typescript:修复 UseEffect Hook(回调+清理函数错误)

socket.io useEffect 清理函数 react

如何取消 useEffect 清理函数中的所有订阅和异步任务?

React Hook useEffect 缺少依赖项(没有在 useEffect 中移动函数)

为啥每次渲染都会调用 `useEffect` 的清理功能?