React Hooks应该避免的5个常见错误

1,902 阅读5分钟

Hook 是 React 16.8 的新增特性,它可以让你在不编写 class 的情况下使用 state,生命周期以及其他的 React 特性,非常受开发者的喜爱。

不过,React Hooks作为高级特性,使用的时候也会有一些 Hook 规则 和注意事项。

本文中,我将讨论在构建 React 应用程序时应避免的 5 个常见 React Hooks 错误

错误1:更改Hooks调用顺序

只在最顶层使用Hook ,不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层以及任何 return 之前调用他们。遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 useStateuseEffect 调用之间保持 hook 状态的正确。(如果你对此感到好奇,我们在下面会有更深入的解释。)

上面是官网的原话,下面我们创建一个场景,解释一下。

我创建了一个基本的 React 组件,组件有一个下拉列表,从列表中选择一个人并显示人员的数据,看错误代码:

1.png

乍一看,很完美,但是控制台会抛出错误。因为useStateuseEffect并不是在第一个return 之前调用的。看一下效果图:

如何改正呢?思考三分钟...

其实很简单,只需要把 useState和useEffect的调用顺序放到 函数体的最上面即可。看图:

把 useState和useEffect的调用顺序放到 函数体的最上面,控制台错误消失了。

错误2:不必要的重新渲染

在组件中,可以使用useStateHook 进行状态处理。虽然它非常简单,但如果使用不当,可能会出现意想不到的问题。

例如,假设一个组件有两个按钮。第一个按钮将触发一个计数器,第二个按钮将根据当前计数器状态发出请求。

3.png

上面的组件运行起来没问题,控制台也没有报错。但是,由于我们在渲染阶段没有使用 counter,每次点击计数器按钮时都会出现不需要的重新渲染。

假如,你需要一个变量,它既能保持状态值(state),又能不触发重新渲染,useRef是更好的选择。改进一下代码:

4.png

错误3:通过 useEffect 处理 Action

使用 useEffect Hook 监听 propstate 变化之后处理一任务。但是,在某些情况下,它会使事情变得更加复杂。

例如:有一个组件获取数据列表并将其渲染到页面上

5.png

fetchPersons组件初始化的时候,第一个useEffect调用了apiCall函数。 在所有的条件的都满足的情况下,第二个useEffect 将会调用onSucces方法。

可以看出,apiCallonSuccess被割裂在两个Hook里面,这样会有两个问题,一是不能保证只有成功了才去触发onSuccess,而是代码可读性比较差,后期维护比较困难。

改进方案是把onSuccess 放到apiCall成功的回调里面,保证只有请求成功的情况下载去调用。如图:

6.png

错误4:丢失useEffect的依赖

useEffectHook 是 React 中最常用的 Hook 之一,默认情况下它总是在每次重新渲染时运行。在某些情况下,每次渲染后都执行清理或者执行 effect 可能会导致性能问题。

如果某些特定值在两次重渲染之间没有发生变化,你可以通知 React 跳过对 effect 的调用,只要传递数组作为 useEffect 的第二个可选参数即可:

useEffect(() => {
  showCount(count)
}, [count]); // 仅在 count 更改时更新

看一下 React官网解释:

如果你要使用此优化方式,请确保数组中包含了所有外部作用域中会随时间变化并且在 effect 中使用的变量,否则你的代码会引用到先前渲染中的旧变量。参阅文档,了解更多关于如何处理函数以及数组频繁变化时的措施内容。

如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([])作为第二个参数。这就告诉 React 你的 effect 不依赖于 props 或 state 中的任何值,所以它永远都不需要重复执行。这并不属于特殊情况 —— 它依然遵循依赖数组的工作方式。

如果你传入了一个空数组([]),effect 内部的 props 和 state 就会一直拥有其初始值。尽管传入 [] 作为第二个参数更接近大家更熟悉的 componentDidMountcomponentWillUnmount 思维模式,但我们有更好的方式来避免过于频繁的重复调用 effect。除此之外,请记得 React 会等待浏览器完成画面渲染之后才会延迟调用 useEffect,因此会使得额外操作很方便。

我们推荐启用 eslint-plugin-react-hooks 中的 exhaustive-deps 规则。此规则会在添加错误依赖时发出警告并给出修复建议。

看一下面一个例子:

7.png

可以看出,点击了按钮四次,但是showCount方法,只输出了一次结果。

正确的做法是,添加count依赖。

useEffect(() => {
  showCount(count)
}, [count]); // 仅在 count 更改时更新

错误5:使用了过期的State

先看一个例子:多次调用更新state的方法。

8.png

多次更改 useState,会被合并成一次,因为 state 只在组件首次渲染的时候被创建。在下一次重新渲染时,useState 返回给我们当前的 state。

如果就像更改三次,怎么办呢?答案是useState参数使用函数的方式

9.png

参考链接

Common React Hooks Mistakes You Should Avoid

最后总结

在使用具有高级和自定义功能的 React Hooks 时往往会犯一些错误。在本文中,讨论了在使用 React Hooks 时应避免的 5 个常见错误。

本人水平有限,如果对本文有任何建议或者发现了错误,欢迎在在评论区分享。

谢谢阅读!!!