React 18 对 Hooks 的影响 :1

简介: React 18 对 Hooks 的影响 :1
🙋🏻‍♀️ 编编拎重点:最近 React 18 发布后,部分改动对我们使用 React Hooks 有一些影响。这篇文章是蚂蚁集团前端工程师尽龙对官方文档的翻译,好让大家清晰的认识到这个改动的背景和影响。

1. 译者前言

最近 React 18 发布后,部分改动对我们使用 React Hooks 有一些影响。这篇文章对官方的文档 Update to remove the "setState on unmounted component warning"[1] 做了翻译,好让大家清晰的认识到这个改动的背景和影响。这是 React 18 对 Hooks 的影响系列第一篇,后续还会再整理其他有影响的改动,欢迎关注不迷路。

2. 翻译

2.1 背景


之前在已经卸载的组件中调用 setState时,会有一个警告,本次我们将这个警告移除了。警告内容如下:

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.

警告:不能在已经卸载的组件中更改 state。这是一个无用的操作,它表明你的项目中存在内存泄漏。要解决这个问题,请在 useEffect 清理函数中取消所有订阅和异步任务。

不幸的是,这个警告经常被误解,并且会误导大家。

它原本是想保证如下示例能正常工作的:

useEffect(() => {
  function handleChange() {
     setState(store.getState())
  }
  store.subscribe(handleChange)
  return () => store.unsubscribe(handleChange)
}, [])

在这个例子中,如果你忘记了在 effect 清理函数中调用 unsubscribe,那肯定是有内存泄漏的。

2.2 为什么说这个警告会误导大家呢?


事实上,上面的场景并不常见。反而如下场景是更常见的:

async function handleSubmit() {
  setPending(true)
  await post('/someapi') // component might unmount while we're waiting
  setPending(false)
}

在上面的代码中,如果发送请求时,组件卸载了,会抛出警告。但是,在这种场景下,警告误导了大家。

这里其实没有内存泄漏:

  • Promise 会很快完成执行,然后内存被垃圾回收机制回收
  • 即使没有很快完成执行,这个警告也是没用的,因为垃圾回收也还是得等 Promise 执行完回收,你啥也不能做

一般,我们会通过如下代码来消除警告:

let isMountedRef = useRef(false)
useEffect(() => {
  isMountedRef.current = true
  return () => {
    isMountedRef.current = false
  }
}, [])
async function handleSubmit() {
  setPending(true)
  await post('/someapi')
  if (!isMountedRef.current) {
    setPending(false)
  }
}

实际上,这种写法是没用的,并没有解决所谓的“内存泄漏”,它仅仅只是抑制了警告。正如前面说的,这里其实是没有内存泄漏的。内存会随着 Promise 执行完而释放,并没有什么在无限执行。

2.3 上述抑制警告方案比不处理更糟糕


上述抑制警告的解决方案,现在非常非常普遍。但它其实没任何好处,反而比不处理更糟糕:

  • 未来,React 会提供一个新能力,在组件卸载不可见时,我们会保存组件现在的 state,但仍会卸载组件。下次加载组件的时候,我们会用之前保存的 state 来渲染组件,以便恢复之前的页面。在组件卸载之后,setPending(false)不会被执行到,所以 pending会一直是 true,那下次恢复组件的时候,看起来是请求没有执行完成,会变的更糟糕。(译者注:关于这一块详细的行为和影响面,下一篇文章介绍)
  • 假设用户点击一个按钮,发起一个网络请求,请求结束后更新 state。为了避免这个警告,有些人会将请求行为放到 useEffect 中,因为在 useEffect 中可以监听到组件卸载,以忽略后续的 state 更新,消除警告。这样代码变的非常不清晰,非常糟糕!就是因为这个错误的警告,会让大家写出更烂的代码。

2.4 移除警告


最终,我们决定移除这个警告。这个警告想解决的订阅问题,在日常代码中并不常见。大部分情况下,它反而会误导大家,为了避免告警写出更烂的代码。希望这个警告的移除,可以让你移除代码中的 isMounted

3. 译者总结

在 ahooks 中的 useUnmountedRef[2]useSafeState[3] 等都是为了解决这个警告而生的。同时我们在 ahooks 中必要的地方,为了避免这个告警,也会在组件卸载后,忽略后续的 setState

目前来看,这些代码是多余的,后续 ahooks 会陆续优化相关场景,但不会太快。因为在 react 16、17 中这个告警仍然会有,会对新人造成不必要的困扰。我们会等 React 18 覆盖面比较广之后,再进行代码优化。

以后在代码中大家应该不需要再考虑这个告警了,不需要再使用 useUnmountedRef[4]useSafeState[5] 等 Hooks 了。

参考资料

[1]

Update to remove the setState on unmounted component warning: https://github.com/reactwg/react-18/discussions/82

[2]

useUnmountedRef: https://ahooks.js.org/hooks/use-unmounted-ref

[3]

useSafeState: https://ahooks.js.org/hooks/use-safe-state

[4]

useUnmountedRef: https://ahooks.js.org/hooks/use-unmounted-ref

[5]

useSafeState: https://ahooks.js.org/hooks/use-safe-state


相关文章
|
1月前
|
前端开发 JavaScript 开发者
深入理解React Hooks:提升前端开发效率的关键
【10月更文挑战第5天】深入理解React Hooks:提升前端开发效率的关键
|
1月前
|
前端开发 JavaScript
React Hooks 全面解析
【10月更文挑战第11天】React Hooks 是 React 16.8 引入的新特性,允许在函数组件中使用状态和其他 React 特性,简化了状态管理和生命周期管理。本文从基础概念入手,详细介绍了 `useState` 和 `useEffect` 的用法,探讨了常见问题和易错点,并提供了代码示例。通过学习本文,你将更好地理解和使用 Hooks,提升开发效率。
68 4
|
1月前
|
前端开发
深入解析React Hooks:构建高效且可维护的前端应用
本文将带你走进React Hooks的世界,探索这一革新特性如何改变我们构建React组件的方式。通过分析Hooks的核心概念、使用方法和最佳实践,文章旨在帮助你充分利用Hooks来提高开发效率,编写更简洁、更可维护的前端代码。我们将通过实际代码示例,深入了解useState、useEffect等常用Hooks的内部工作原理,并探讨如何自定义Hooks以复用逻辑。
|
1月前
|
前端开发 JavaScript API
探索React Hooks:前端开发的革命性工具
【10月更文挑战第5天】探索React Hooks:前端开发的革命性工具
|
12天前
|
前端开发 JavaScript
深入探索React Hooks:从useState到useEffect
深入探索React Hooks:从useState到useEffect
|
22天前
|
前端开发 JavaScript 开发者
“揭秘React Hooks的神秘面纱:如何掌握这些改变游戏规则的超能力以打造无敌前端应用”
【10月更文挑战第25天】React Hooks 自 2018 年推出以来,已成为 React 功能组件的重要组成部分。本文全面解析了 React Hooks 的核心概念,包括 `useState` 和 `useEffect` 的使用方法,并提供了最佳实践,如避免过度使用 Hooks、保持 Hooks 调用顺序一致、使用 `useReducer` 管理复杂状态逻辑、自定义 Hooks 封装复用逻辑等,帮助开发者更高效地使用 Hooks,构建健壮且易于维护的 React 应用。
29 2
|
27天前
|
前端开发 开发者
React 提供的其他重要 Hooks
【10月更文挑战第20天】React 提供了一系列强大的 Hooks,除了 `useRef` 之外,还有许多其他重要的 Hooks,它们共同构成了函数式组件开发的基础。
35 6
|
4天前
|
缓存 前端开发 开发者
深入理解React Hooks,打造高效响应式UI
深入理解React Hooks,打造高效响应式UI
13 0
|
1月前
|
前端开发 JavaScript 开发者
React Hooks
10月更文挑战第13天
34 1
|
1月前
|
前端开发