原文作者:Dan Abramov
译者:UC 国际研发 Jothy
写在最前:欢迎你来到“UC国际技术”公众号,我们将为大家提供与客户端、服务端、算法、测试、数据、前端等相关的高质量技术文章,不限于原创与翻译。
编者按:英文原文带有大量外链,由于微信的限制不能很好展示,您可选择「阅读原文」获得更好的阅读体验。:-)
随着 React 发布 16.8 版本,React Hooks 也发布稳定版本啦!
什么是 Hooks?
Hooks 允许你在不编写 class 的情况下使用状态(state)和其他 React 特性。 你还可以构建自己的 Hooks, 跨组件共享可重用的有状态逻辑。
如果你以前从未听说过 Hooks, 你可能会觉得这些资源很有趣:
- Hooks 介绍 解释了我们给 React 添加 Hooks 的原因。
- Hooks 概览 是对内置 Hooks 的快速概述。
- 构建自己的 Hooks 演示了如何使用自定义 Hooks 重用代码。
- 理解 React Hooks 探索了那些被 Hooks 解锁的新的可能。
- useHooks.com 展示了由社区维护的 Hooks 用法和 demos.
你不必现在就学习 Hooks. Hooks 没有重大变化,我们不计划从 React 中移除 class. Hooks FAQ 描述了我们逐步采纳的策略。
无重大重写
我们不建议你为了马上应用 Hooks 而重写现有应用。相反,我们建议你尝试在一些新的组件中使用 Hooks, 并且让我们了解你的想法。 使用 Hooks 的代码将与使用 class 的现有代码并行工作。
我现在可以用 Hooks 了吗?
可以的! 从 16.8.0 版本开始,React 包含一个稳定的 React Hooks 实现,可用于:
- React DOM
- React DOM 服务器(Server)
- React 测试渲染器(Test Renderer)
- React 浅层渲染器(Shallow Renderer)
请注意,要启用 Hooks, 所有 React 包都必须升级到 16.8.0 或更高版本。 如果你忘记更新诸如 React DOM 之类的包,Hooks 将无法运行。
React Native 将在 0.59 版本 支持 Hooks.
工具支持
React DevTools 现已支持 React Hooks, React 最新的 Flow 和 TypeScript 定义也支持它们。我们强烈建议你启用名为 eslint-plugin-react-hooks 的新 lint 规则来强制执行 Hooks 的最佳实践。Create React App 将很快包含它。
规划
我们在最近发布的 React 路线图中描述了我们未来几个月的计划。
请注意,React Hooks 尚未涵盖所有 class 的用例,但已经很接近了。 目前,只有 getSnapshotBeforeUpdate() 和 componentDidCatch() 方法没有等价的 Hooks API, 且这些生命周期相对不常见。 如果你想用 Hooks, 你可以在你正在写的大部分新代码中使用它。
即使仍处于 alpha 状态,React 社区也使用 Hooks 为动画(animations),表单(forms),订阅(subscriptions),与其他库的集成(integrating)等创建了许多有趣的示例和用法。 我们为 Hooks 而雀跃 ,因为它们使代码更易重用,帮助你以更简单的方式编写组件,创建绝佳的用户体验。 我们迫不及待想知道你接下来会创造什么!
测试 Hooks
我们在这个版本中添加了一个名为 ReactTestUtils.act() 的新 API. 它可确保测试的行为与浏览器中的行为更加匹配。我们建议将所有代码渲染和组件更新触发封装到 act() 调用中。测试库也可以用它封装 API(举个例子,react-testing-library 的 render 和 fireEvent 工具就是这样做的)。
例如,此页面中的计数器示例可以这样进行测试:
对 act() 的调用也会刷新它们内部的 effects.
如果你需要测试自定义 Hook, 你可以在测试时创建组件,并使用它的 Hook. 然后就可以测试你写的组件了。
为了减少重复样板,我们建议使用 react-testing-library, 它鼓励程序员编写模拟用户使用组件的行为的测试。
致谢
我们想向所有在 Hooks RFC 中分享反馈意见的人致谢。 我们已经阅读了你们的所有评论,并根据它们对最终 API 进行了一些调整。
安装
React {#react}
React 16.8.0 版本已发布到 NPM 注册表。
使用 Yarn 安装 React 16, 请运行:
使用 NPM 安装 React 16, 请运行:
我们还通过 CDN 提供 React 的 UMD 构建版本:
详情请访问详细的安装。
React Hooks 的 ESLint 插件
注意
综上所述,我们强烈建议你使用 eslint-plugin-react-hooks lint 规则。
如果你正在使用 Create React App, 而不是手动配置 ESLint,你可以等待下一版本的 react-scripts, 届时将包含此规则。
假设你已经安装了 ESLint, 请运行:
然后添加以下 ESLint 配置:
更新日志
React {#react-1}
- 新增 Hooks —— 一种在不编写 class 的情况下使用状态(state)和其他 React 特性的方法。(@acdlite 等人提出于 #13968)
- 改进 useReducer Hook 延迟初始化 API. (@acdlite 提出于 #14723)
React DOM {#react-dom}
- 避免为 useState 和 useReducer Hooks 传入相同值时进行的渲染。 (@acdlite 提出于 #14569)
- 不比较传递给 useEffect/useMemo/useCallback Hooks 的第一个参数。 (@gaearon 提出于 #14654)
- 使用 Object.is 算法比较 useState 和 useReducer 的值。 (@Jessidhia 提出于 #14752)
- 支持传递给 React.lazy() 的同步 thenable. (@gaearon 提出于 #14626)
- 在严格模式(仅限 DEV)中使用 Hooks 两次渲染组件以匹配 class 行为。 (@gaearon 提出于 #14654)
- 在开发模式中 Hook 顺序不匹配时警告。 (@threepointone 提出于 #14585 及 @acdlite 提出于 #14591)
Effect 清理功能必须返回 undefined 或函数。不允许包含 null 在内的其他所有值。(@acdlite 提出于 #14119)
React 测试渲染器
- 支持浅层渲染器中的 Hooks. (@trueadm 提出于 #14567)
- 在浅层渲染器中存在 getDerivedStateFromProps 的情况下,修复 shouldComponentUpdate 中的错误状态。 (@chenesan 提出于 #14613)
- 添加 ReactTestRenderer.act() 和 ReactTestUtils.act() 以进行批处理更新,以便测试更接近真实行为。 (@threepointone 提出于 #14744)
ESLint 插件: React Hooks {#eslint-plugin-react-hooks}
- 首次发布。 (@calebmer 提出于 #13968)
- 修复循环后的报告。 (@calebmer 及 @Yurickh 提出于 #14661)
- 不要把错误的抛出当作违反规则。 (@sophiebits 提出于 #14040)
Hooks 自 Alpha 版本之后的更新日志 {#hooks-changelog-since-alpha-versions}
上述更改日志包含自上次稳定版本(16.7.0)以来的所有重要更改。 与我们的所有 minor 版本一样,这些更改都不会破坏向后兼容性。
如果你正在使用来自 React alpha 版本的 Hooks, 请注意此版本确实包含对 Hooks 的一些小的重大更改。 我们不建议在生产代码中依赖 alpha. 我们发布它们是为了在 API 稳定之前根据的社区反馈进行更改。
以下是自第一个 alpha 版本发布以来,我们对 Hooks 所做的所有重大更改:
- 删除
useMutationEffect
. (@sophiebits 提出于 #14336) - 将 useImperativeMethods 重命名为
useImperativeHandle
. (@threepointone 提出于 #14565) - 避免为 useState 和 useReducer Hooks 传入相同值时进行的渲染。 (@acdlite 提出于 #14569)
- 不比较传递给 useEffect/useMemo/useCallback Hooks 的第一个参数。 (@gaearon 提出于 #14654)
- 使用 Object.is 算法比较 useState 和 useReducer 的值。 (@Jessidhia 提出于 #14752)
- 在严格模式下仅使用 Hooks 两次渲染组件(仅限 DEV)。 (@gaearon 提出于 #14654)
- 改进 useReducer Hook 延迟初始化 API. (@acdlite 提出于 #14723)