You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
1. 译者前言
最近 React 18 发布后,部分改动对我们使用 React Hooks 有一些影响。这篇文章对官方的文档《Update to remove the "setState on unmounted component" warning》做了翻译,好让大家清晰的认识到这个改动的背景和影响。
这是 React 18 对 Hooks 的影响系列第一篇,后面我还会整理其它有影响的改动,关注不迷路。
2. 翻译
2.1 背景
之前在已经卸载的组件中调用
setState
时,会有一个警告,本次我们将这个警告移除了。警告内容如下:不幸的是,这个警告经常被误解,并且会误导大家。
它原本是想保证如下示例能正常工作的:
在这个例子中,如果你忘记了在 effect 清理函数中调用
unsubscribe
,那肯定是有内存泄漏的。2.2 为什么说这个警告会误导大家呢?
事实上,上面的场景并不常见。反而如下场景是更常见的:
在上面的代码中,如果发送请求时,组件卸载了,会抛出警告。但是,在这种场景下,警告误导了大家。
这里其实没有内存泄漏:
一般,我们会通过如下代码来消除警告:
实际上,这种写法是没用的,并没有解决所谓的“内存泄漏”,它仅仅只是抑制了警告。正如前面说的,这里其实是没有内存泄漏的。内存会随着 Promise 执行完而释放,并没有什么在无限执行。
2.3 上述抑制警告方案比不处理更糟糕
上述抑制警告的解决方案,现在非常非常普遍。但它其实没任何好处,反而比不处理更糟糕:
未来,React 会提供一个新能力,在组件卸载不可见时,我们会保存组件现在的 state,但仍会卸载组件。下次加载组件的时候,我们会用之前保存的 state 来渲染组件,以便恢复之前的页面。
在组件卸载之后,
setPending(false)
不会被执行到,所以pending
会一直是true
,那下次恢复组件的时候,看起来是请求没有执行完成,会变的更糟糕。(译者注:关于这一块详细的行为和影响面,下一篇文章介绍)假设用户点击一个按钮,发起一个网络请求,请求结束后更新 state。为了避免这个警告,有些人会将请求行为放到 useEffect 中,因为在 useEffect 中可以监听到组件卸载,以忽略后续的 state 更新,消除警告。这样代码变的非常不清晰,非常糟糕!就是因为这个错误的警告,会让大家写出更烂的代码。
2.4 移除警告
最终,我们决定移除这个警告。这个警告想解决的订阅问题,在日常代码中并不常见。大部分情况下,它反而会误导大家,为了避免告警写出更烂的代码。
希望这个警告的移除,可以让你移除代码中的
isMounted
。3. 译者总结
在 ahooks 中的 useUnmountedRef、useSafeState 等都是为了解决这个警告而生的。同时我们在 ahooks 中必要的地方,为了避免这个告警,也会在组件卸载后,忽略后续的
setState
。目前来看,这些代码是多余的,后续 ahooks 会陆续优化相关场景,但不会太快。因为在 react 16、17 中这个告警仍然会有,会对新人造成不必要的困扰。我们会等 React 18 覆盖面比较广之后,再进行代码优化。
以后在代码中大家应该不需要再考虑这个告警了,不需要再使用 useUnmountedRef、useSafeState 等 Hooks 了。
The text was updated successfully, but these errors were encountered: