本文最初发布于 Medium 网站,经原作者授权由 InfoQ 中文站翻译并分享。
在过去,像状态和生命周期函数这样的 React 特性只适用于基于类的组件。基于函数的组件被称为哑(dumb)、瘦(skinny)或表示(presentational)组件,因为它们无法访问状态和生命周期函数。
但是自从 React Hooks 发布以来,基于函数的组件已升格为 React 的一等公民。它使函数组件能够以新的方式编写、重用和共享 React 代码。
在这篇文章中,我将分享 6 个关于 React Hooks 的技巧。你可以把它当作一份指南,在将 Hooks 实现到组件中时可以拿来参考。
遵守 Hooks 规则
这条规则看起来是句废话,但无论是新手还是经验丰富的 React 开发人员,都常常会忘记遵循 React Hooks 的规则。这些规则包括:
仅在顶级调用 Hooks
不要在循环、条件和嵌套函数内调用 Hooks。当你想有条件地使用某些 Hooks 时,请在这些 Hooks 中写入条件。
不要这样做:
相比之下,你应该这样做:
这条规则能确保每次渲染组件时都以相同的顺序调用 Hooks。这样一来,React 就能在多个 useState 和 useEffect 调用之间正确保留 Hooks 的状态。
仅从函数组件调用 Hooks
不要从常规 JavaScript 函数中调用 Hooks。仅从函数组件或自定义 Hooks 中调用 Hooks。
遵循这一条规则,可以确保组件中的所有状态逻辑在源代码中都能清晰可见。
使用 ESLint 的 React Hooks 插件
React 团队还创建了一个名为 eslint-plugin-react-hooks 的 ESLint 插件,以帮助开发人员在自己的项目中以正确的方式编写 React Hooks。这个插件能够帮助你在尝试运行应用程序之前捕获并修复 Hooks 错误。
它有两条简单的规则:
react-hooks/rules-of-hooks
react-hooks/exhaustive-deps
第一条规则只是强制你的代码符合我在第一个技巧中说明的 Hooks 规则。第二个规则,exhaustive-deps 用于实施 useEffect 的规则:effect 函数中引用的每个值也应出现在依赖项数组中。
例如,下面这个 userInfo 组件会触发 exhaustive-deps 警告,因为 userId 变量在 useEffect 内部被引用,但未在依赖项数组中传递:
尽管 exhaustive-deps 这条规则看起来很烦人,但它能帮助你避免由未列出的依赖项引发的错误。
以正确的顺序创建函数组件
当创建类组件时,遵循一定的顺序可以帮助你更好地维护和改进 React 应用程序代码。
首先调用构造器并启动状态。然后编写生命周期函数,接着编写与组件作业相关的所有函数。最后编写 render 方法:
编写函数组件时并没有构造器和生命周期函数,因此你可能会犯糊涂,因为这种结构并不像类组件里那样是强制的:
但就像类组件一样,为函数组件创建定义的结构能够改善项目的可读性。
建议先使用 useState Hook 声明状态变量,然后使用 useEffect Hook 编写订阅,接着编写与组件作业相关的其他函数。
最后,你得返回要由浏览器渲染的元素:
通过强制一种结构,可以让代码流在众多组件之间保持一致,看起来也比较亲切。
useState 的用法可以和类组件的状态完全一致,不只用于单个值
许多 useState 示例会向你展示如何通过声明多个变量来声明多个状态:
但是 useState 实际上既可以处理数组也可以处理对象。你依旧可以将相关数据分组为一个状态变量,如以下示例所示:
这里有一个警告。使用 useState 的更新函数更新状态时,以前的状态会替换为新状态。这与类组件的 this.setState 不同,后者的新类中,新状态会与旧状态合并:
为了保留以前的状态,你需要创建将当前状态值传递到自身中的回调函数来手动合并它。由于上面的示例已将 user 变量分配为状态值,因此可以将其传递给 setUser 函数,如下所示:
根据数据在应用程序生命周期中的变化情况,建议在各个值彼此独立时将状态拆分为多个变量。
但是对于某些情况,例如构建一个简单的表单,最好将状态分组在一起,以便更轻松地处理更改和提交数据。
简而言之,你需要在多个 useState 调用和单个 useState 调用之间保持平衡。
使用自定义 Hooks 共享应用程序逻辑
在构建应用程序时,你会注意到一些应用程序逻辑会在许多组件中一次又一次地使用。
随着 React Hooks 的发布,你可以将组件的逻辑提取到可重用的函数中作为自定义 Hooks,如我在以下文章中所展示的那样:
可扩展 React 项目的 6 个技巧和最佳实践:
https://blog.bitsrc.io/best-practices-and-tips-for-a-scalable-react-application-db708ae49227
你可以使用 Bit 之类的工具将 Hooks 发布到单个集合中,这样你就可以在不同的应用程序中安装和重用它们。它不需要你创建一个全新的“Hooks 库”项目,你可以一点点将新的 Hooks 从任何项目“推入”你的共享集合。
针对这个方法,唯一要强调的是你不能在类组件中使用 Hooks。所以如果你的项目中还有老式的类组件,就需要将它们转换为函数,或者使用其他可重用逻辑模式(HOC 或渲染 Props)。
使用 useContext 避免 prop drilling
prop-drilling 是 React 应用程序中的常见问题,指的是将数据从一个父组件向下传递,经过各层组,直到到达指定的子组件,而其他嵌套组件实际上并不需要它们。
考虑以下示例:
https://bit.dev/nsebhastian/tutorial-examples/prop-drill-example?example=5f941e4445728c001924150a
从示例中可以看到,即使 Hello 组件不需要 props,App 组件也会通过 Hello 组件将 name props 传递给 Greeting 组件。
React Context 是一项功能,它提供了一种通过组件树向下传递数据的方法,这种方法无需在组件之间手动传 props。父组件中定义的 React Context 的值可由其子级通过 useContext Hook 访问。
在下面的示例中,我将 name 数据(而非 props)传递给 Context Provider,给代码做了重构:
https://bit.dev/nsebhastian/tutorial-examples/prop-drill-example?example=5f941fae45728c001924150e
App 的任何子组件都可以通过 useContext Hook 访问数据。可以从文档中了解有关 useContext Hook 的更多信息:
https://reactjs.org/docs/hooks-reference.html#usecontext
总结
React Hooks 是 React 库的重要补充,因为它允许你用独一无二的方式编写、重用和共享 React 代码。
随着 Hooks 开始改变开发人员编写 React 组件的方式,需要一套新的编写 React Hooks 的最佳实践,以便多个团队之间更轻松地开发和协作。
虽然本文肯定还有遗漏的内容,但我希望以上分享的技巧能多少帮助你在项目中以正确的方式编写 React Hooks。
查看英文原文:
https://blog.bitsrc.io/best-practices-with-react-hooks-69d7e4af69a7
评论 2 条评论