Hook 本质就是 JavaScript 函数,但是在使用它时需要遵循两条规则。

只在最顶层使用 Hook

不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层调用他们。遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 useState 和 useEffect 调用之间保持 hook 状态的正确。

只在 React 函数中调用 Hook

不要在普通的 JavaScript 函数中调用 Hook。你可以:1、在 React 的函数组件中调用 Hook 2、在自定义 Hook 中调用其他 Hook

官方发布了一个名为 eslint-plugin-react-hooks 的 ESLint 插件来强制执行这两条规则。如果你想尝试一下,可以将此插件添加到你的项目中。

那么 React 怎么知道哪个 state 对应哪个 useState?答案是 React 靠的是 Hook 调用的顺序。因为我们的示例中,Hook 的调用顺序在每次渲染中都是相同的,所以它能够正常工作:

function Form() {// 1. 使用 'Mary' 初始化变量名为 name 的 stateconst [name, setName] = useState('Mary');// 2. 添加 effect 以保存 form 操作useEffect(function persistForm() {localStorage.setItem('formData', name);});// 3. 使用 'Poppins' 初始化变量名为 surname 的 stateconst [surname, setSurname] = useState('Poppins');// 4. 添加 effect 以更新标题useEffect(function updateTitle() {document.title = name + ' ' + surname;});
}

Hook 的调用顺序在每次渲染中都是相同的。

// ------------
// 首次渲染
// ------------
useState('Mary')           // 1. 使用 'Mary' 初始化变量名为 name 的 state
useEffect(persistForm)     // 2. 添加 effect 以保存 form 操作
useState('Poppins')        // 3. 使用 'Poppins' 初始化变量名为 surname 的 state
useEffect(updateTitle)     // 4. 添加 effect 以更新标题// -------------
// 二次渲染
// -------------
useState('Mary')           // 1. 读取变量名为 name 的 state(参数被忽略)
useEffect(persistForm)     // 2. 替换保存 form 的 effect
useState('Poppins')        // 3. 读取变量名为 surname 的 state(参数被忽略)
useEffect(updateTitle)     // 4. 替换更新标题的 effect

只要 Hook 的调用顺序在多次渲染之间保持一致,React 就能正确地将内部 state 和对应的 Hook 进行关联。但如果我们将一个 Hook (例如 persistForm effect) 调用放到一个条件语句中会发生什么呢?

 // 条件语句中使用 Hook 违反第一条规则
if (name !== '') {useEffect(function persistForm() {localStorage.setItem('formData', name);});
}

在第一次渲染中 name !== '' 这个条件值为 true,所以我们会执行这个 Hook。但是下一次渲染时我们可能清空了表单,表达式值变为 false。此时的渲染会跳过该 Hook,Hook 的调用顺序发生了改变:

useState('Mary')           // 1. 读取变量名为 name 的 state(参数被忽略)
// useEffect(persistForm)  // 此 Hook 被忽略!
useState('Poppins')        // 2 (之前为 3)。读取变量名为 surname 的 state 失败
useEffect(updateTitle)     // 3 (之前为 4)。替换更新标题的 effect 失败

React 不知道第二个 useState 的 Hook 应该返回什么。React 会以为在该组件中第二个 Hook 的调用像上次的渲染一样,对应的是 persistForm 的 effect,但并非如此。从这里开始,后面的 Hook 调用都被提前执行,导致 bug 的产生。

这就是为什么 Hook 需要在我们组件的最顶层调用。如果我们想要有条件地执行一个 effect,可以将判断放到 Hook 的内部:

useEffect(function persistForm() {// 将条件判断放置在 effect 中if (name !== '') {localStorage.setItem('formData', name);}
});

注意:如果使用了提供的 lint 插件,就无需担心此问题。不过你现在知道了为什么 Hook 会这样工作,也知道了这个规则是为了避免什么问题。

理解 Hook 规则相关推荐

  1. firewalld中理解直接规则和富语言

    firewalld 中理解直接规则 firewalld提供了'direct interface" (直接接口), 它允许管理员手动编写的iptables. ip6tables 和ebtabl ...

  2. Hook 规则以及自定义Hook

    文章目录 Hook规则 只在最顶层使用 Hook 只在 React 函数中调用 Hook 自定义Hook Hook规则 只在最顶层使用 Hook 不要在循环,条件或嵌套函数中调用 Hook, 确保总是 ...

  3. 聊聊高并发(三十六)Java内存模型那些事(四)理解Happens-before规则

    在前几篇将Java内存模型的那些事基本上把这个域底层的概念都解释清楚了,聊聊高并发(三十五)Java内存模型那些事(三)理解内存屏障 这篇分析了在X86平台下,volatile,synchronize ...

  4. happens-before规则——理解happens-before规则

    文章目录 写在前面 JMM 的设计 总结 happens-before 的定义 as-if-serial 语义 happens-before 规则 实例1 实例2 实例3 参考资料 写在前面 happ ...

  5. 正确理解55-38-7规则

    55-38-7规则 人物简介 理论概念 实验设计[2] 误解总结 人物简介 Albert Mehrabian(1939年)[1]生于伊朗的一个亚美尼亚家庭.最开始从事工程学科的学术研究.Mehrabi ...

  6. [转]如何理解矩阵乘法的规则(两个矩阵相乘法则的推导,从对方程组解方程演化而来)

    [转]如何理解矩阵乘法的规则 转自(http://news.cnblogs.com/n/528288/) 我加入了自己的理解. 作者: 阮一峰 大多数人在高中,或者大学低年级,都上过一门课<线性 ...

  7. 如何使用React Hook

    class组件和函数组件 我们希望编写代码的时候,尽可能将整块可复用的部分封装起来.这样可以一定程度提高代码的内聚性,将其耦合性,使得程序开发变得更加可维护.通常情况下,我们将代码块抽离成组件来实现封 ...

  8. react04-Ref与Hook

    1.Refs 本小结参考博文 官方介绍 在典型的 React 数据流中,props 是父组件与子组件交互的唯一方式.要修改一个子组件,你需要使用新的 props 来重新渲染它.但是,在某些情况下,你需 ...

  9. 深入理解 netfilter 和 iptables

    Netfilter (配合 iptables)使得用户空间应用程序可以注册内核网络栈在处理数据包时应用的处理规则,实现高效的网络转发和过滤.很多常见的主机防火墙程序以及 Kubernetes 的 Se ...

最新文章

  1. 数据库 mysql 表设计,数据删除
  2. 腾讯AI Lab视觉计算中心招聘计算机视觉算法实习生
  3. JS 中 this 的指向
  4. 两个链表生成相加链表
  5. MySQL索引的坑,谁踩谁知道……
  6. 基于Boost::beast模块的异步HTTP客户端
  7. 现代中小企业IT基础平台建设 - 完整案例实战(00_序)
  8. 中点击按钮新建widget_iOS 14-Widget开发
  9. Zepto自定义模块打包构建
  10. 软件架构(7)---软件架构设计-五视图方法论
  11. Docker发布镜像至Docker Hub
  12. ROS学习笔记6(理解ROS话题)
  13. mysql装了一半卡住了_mysql安装问题:安装到configuration overview卡住了
  14. python中的常量_深入理解Python中的内置常量
  15. BugBugBugBugBugBugBugBugBugBugBugBugBugBugBug
  16. 多线程编程(16) - 多线程同步之 WaitableTimer (等待定时器对象)[续二]
  17. 800道Python习题,花了一个月终于整理出来了,挑战一下自己能做对多少题
  18. PreparedStatement类详解以及案例
  19. Linux与Windows的区别与比较,及Linux基本命令
  20. MIC(最大信息系数)

热门文章

  1. GitHub CEO 回应源代码泄露:没有黑客!没有被入侵!
  2. 如何用 Python 画一个纸飞机?| 原力计划
  3. Google 搜索点击量不到 50%?
  4. 物联网 ToB 的背后,开发者应了解什么?| CSDN 博文精选
  5. 为什么说“大公司的技术顽疾根本挽救不了”?
  6. 史上第一代图形浏览器往事
  7. 倘若马克·扎克伯格 15 年前没有辍学......
  8. “十亿赌约”,雷军输,董明珠胜?
  9. GitHub 近两万 Star!深度学习 500 问带你入门人工智能!| 技术头条
  10. 技术无价,“悟”有所值——UCan下午茶这一年