React useEffect清理函数运行多次?

8

我是一名React Hook新手...

以这个例子为例

useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

来自文档:

React在组件卸载时执行清理操作。但是,正如我们之前学到的那样,effect会在每次渲染时运行而不仅仅是一次。这就是为什么React在下次运行effect之前会清除上一次渲染的副作用。

那么这是否意味着unsubscribeFromFriendStatus只在组件卸载时运行一次还是每次渲染都运行呢?

扩展我的问题:

如果unsubscribeFromFriendStatus每次渲染时都运行,并且仅通过使用可选的第二个参数来跳过它...那么是否会使原始的componentWillMountcomponentWillUnmount的显式执行更加困难?例如,我想在componentWillMount时进行subscribe,并且只在componentWillUnmount时运行unsubscribe


根据文档,这就是为什么React在下一次运行效果之前清除上一次渲染的效果。所以,是的,它会在每次渲染时运行。 - ravibagul91
1个回答

6

那是不是意味着unsubscribeFromFriendStatus只在组件卸载时运行一次,还是每次渲染都会运行?

unsubscribeFromFriendStatus在每次重新渲染时运行

即使props.friend.id从未更改,每次重新渲染都会取消订阅并重新订阅。

为了改进这个问题,只需要props.friend.id更改时才运行effect。可以通过将其添加为useEffect()的依赖项来实现。

useEffect(
  () => { /* subscription */ }
  , [props.friend.id] // add as dependency
)

这是否会使得实现componentWillMount和componentWillUnmount的原始显式执行更加困难呢?比如说,我想在componentWillMount时进行订阅,并且只有在componentWillUnmount时运行取消订阅?
使用旧的props.friend.id值维护旧订阅是没有意义的。
订阅使用资源(websocket或observer)。在componentWillUnmount期间取消订阅仅取消了props.friend.id的最新值。
那么,早期的订阅会发生什么情况?不会被释放。 因此,您将拥有内存泄漏

1
也许 subscribeunsubscribe 不是一个好的例子,因为它违反了 open lateclose early 的原则,但假设我只想在 componentWillMount 时执行某些操作,在 componentWillUnmount 时执行其他操作呢? - James Lin
1
如果您只想运行一次效果,只需将[]作为第二个参数添加即可。 - Joseph D.
但是这个 once 没有指定何时运行?我想要它在“开始”时运行,另一个在“结束”时运行。 - James Lin
2
@JamesLin 传递一个空数组 [] 只会在挂载和卸载时运行 effect。您可以在此部分阅读更多信息:https://reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect - onoya
现在明白了。我是在自己搞混了。 - James Lin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接