[译] React Hooks: 没有魔法,只是数组 原文链接: medium.com/@ryardley/r…

我是 React 新特性 Hooks 的粉丝。但是,在你使用 React Hooks的过程中,有一些看上去 很奇怪的限制 。在本文里,对于那些还在为了理解这些限制而苦苦挣扎的同志,我尝试通过一些列图表的方式,来解释为什么会存在这些限制。

理解hooks怎么运行

我听说很多同学都对hooks像魔法一般的效果感到困惑,因此我将尝试通过浅显的方式,来演示hooks是怎么运行的。

hooks的原则

react团队在怎么使用hooks的 官方文档 中,强调了两点主要的使用原则:

  • 不要 在 循环、条件语句或者嵌套函数中调用hooks

  • 只能在 React 函数组件中调用hooks

第二点我认为是显而易见的。为了给 函数组件 增加一些能力(比如 state,类声明周期方法),你当然需要通过一种方式,来把这种能力赋给函数组件,这种方式就是使用hooks。

然而,第一点规则,很容易让人感到困惑。不就是使用一个 API 么,为什么还有这么多限制呢。这也正是我将要在下文里解释的。

hooks中的state管理,只是在操作数组

为了更加清晰的理解hooks,让我们来看看怎么简单实现hooks API。

请注意,下面代码只是一个demo,是为了让我们理解hooks大概是怎么运作的。这不是 React 中的真正内部实现。

怎么实现 useState 呢?

让我们通过一个例子来演示,useState内部大概是怎么运作的。

组件代码如下:

function RenderFunctionComponent() {const [firstName, setFirstName] = useState("Rudi");const [lastName, setLastName] = useState("Yardley");
​return (<Button onClick={() => setFirstName("Fred")}>Fred</Button>);
}
复制代码

useState 实现的功能是,你能通过这个hook返回的 数组 中第二个元素,作为修改这个state的一个setter方法。

那么,React可能会怎么来实现 useState 呢?

让我们来想想react内部会怎么来实现 useState 呢。在下面的实现里,state 是存放在被render的组件外面,并且这个state不会和其他组件共享,同时,在这个组件后续render中,能够通过特定的作用域方式,访问到这个state。

1) state初始化

创建两个空数组,分别用来存放 setters 和 state,将 指针 指到 0 的位置:

2) 组件首次render

当首次render这个函数组件的时候。

每一个 useState 调用,当 首次 执行的时候,在 setter 数组里加入一个 setter 函数(和对应的数组index关联);然后,将 state 加入对应的 state 数组里:

3) 组件后续(非首次)render

后续组件的每次render,指针都会重置为 0 ,每调用一次 useState,都会返回指针对应的两个数组里的 state 和 setter,然后将指针位置 +1。

4)setter调用处理

每一个 setter 函数,都关联了对应的指针位置。当调用某个 setter 函数式,就可以通过这个函数所关联的指针,找到对应的 state,修改state数组里对应位置的值:

最后来看看useState简单的实现

let state = [];
let setters = [];
let firstRun = true;
let cursor = 0;
​
function createSetter(cursor) {return function setterWithCursor(newVal) {state[cursor] = newVal;};
}
​
// This is the pseudocode for the useState helper
export function useState(initVal) {if (firstRun) {state.push(initVal);setters.push(createSetter(cursor));firstRun = false;}
​const setter = setters[cursor];const value = state[cursor];
​cursor++;return [value, setter];
}
​
// Our component code that uses hooks
function RenderFunctionComponent() {const [firstName, setFirstName] = useState("Rudi"); // cursor: 0const [lastName, setLastName] = useState("Yardley"); // cursor: 1
​return (<div><Button onClick={() => setFirstName("Richard")}>Richard</Button><Button onClick={() => setFirstName("Fred")}>Fred</Button></div>);
}
​
// This is sort of simulating Reacts rendering cycle
function MyComponent() {cursor = 0; // resetting the cursorreturn <RenderFunctionComponent />; // render
}
​
console.log(state); // Pre-render: []
MyComponent();
console.log(state); // First-render: ['Rudi', 'Yardley']
MyComponent();
console.log(state); // Subsequent-render: ['Rudi', 'Yardley']
​
// click the 'Fred' button
​
console.log(state); // After-click: ['Fred', 'Yardley']
复制代码

为什么hooks的调用顺序不能变呢?

如果我们根据某些外部变量,或者组件自身的state,改变hooks的调用顺序,会有什么后果呢?

我们来演示下 错误的 做法:

let firstRender = true;
​
function RenderFunctionComponent() {let initName;if(firstRender){[initName] = useState("Rudi");firstRender = false;}const [firstName, setFirstName] = useState(initName);const [lastName, setLastName] = useState("Yardley");
​return (<Button onClick={() => setFirstName("Fred")}>Fred</Button>);
}
复制代码

上面代码里,我们第一个 useState 是在一个 条件分支里。我们来看看这样引入的bug。

1) 第一次render

第一个render之后,我们的两个state,firstName 和 lastName 都对应了正确的值。接下来看看组件第二次render的时候,会发生什么情况。

2) 第二次render

第二次render之后,我们的两个state, firstName和 lastName 都成了 Rudi。这显然是错误的,必须要避免这样使用hooks!但是这也给我们演示了,hooks的调用顺序,为什么不能改变。

react团队明确强调了hooks的2个使用原则,如果不按照这些原则来使用hooks,将会导致我们数据的不一致性!

将hooks的操作想象成数组的操作,你可能不太会违背这些原则

OK,现在你应该清楚,为什么我们不能在条件块或者循环语句里调用hooks了。因为调用hooks的过程中,我们是在操作数组上的指针,如果你在多次render中,改变了hooks的调用顺序,将导致数组上的指针和组件里的 useState 不匹配,从而返回错误的 state 以及 setter 。

结论

希望我基本讲明白了,hooks调用顺序的大概原理。hooks是对react生态的一个很好的优化。人们对hooks感到兴奋,是有原因的。如果你将hooks的操作,当做数组一样来看待,那么你一般不会违背hooks的使用原则。

转载于:https://juejin.im/post/5ce8071ff265da1bd30534c9

[译] React Hooks: 没有魔法,只是数组相关推荐

  1. mounty不可重新挂载因为先前没有完全卸载_【译】React Hooks测试完全指南

    原文地址:https://www.toptal.com/react/testing-react-hooks-tutorial 2018年底,React在16.8版本中引入了Hooks.它们(译注:指R ...

  2. 【译】什么是React Hooks

    原文:What are React Hooks? 作者:Robin Wieruch 译者:博轩 React Hooks 于 2018年10月的React Conf 中引入,作为在 React 函数组件 ...

  3. react hooks使用_何时使用React Suspense和React Hooks

    react hooks使用 React Suspense对Monad就像钩子对应用符号一样 (React Suspense is to a Monad as Hooks are to Applicat ...

  4. react hooks使用_如何使用React和Hooks检测外部点击

    react hooks使用 by Andrei Cacio 通过安德烈·卡西奥(Andrei Cacio) 如何使用React和Hooks检测外部点击 (How to detect an outsid ...

  5. 探React Hooks

    前言 众所周知,hooks在 React@16.8 中已经正式发布了.而下周周会,我们团队有个同学将会仔细介绍分享一下hooks.最近网上呢有不少hooks的文章,这不免激起了我自己的好奇心,想先行探 ...

  6. 使用React Hooks你可能会忽视的作用域问题

    前言 其实React Hooks已经推出来一段时间了,直到前一阵子才去尝试了下,看到的一些博客都是以API的使用居多,还有一些是对于原理的解析.而我这篇文章想写的是关于React Hooks使用中的作 ...

  7. dw按钮图片滚动js_使用 React Hooks 实现仿石墨的图片预览插件(巨详细)

    点击上方"前端教程",选择"星标" 每天前端开发干货第一时间送达! 作者:DARRELL https://juejin.im/post/5e9bf299f265 ...

  8. 通过 React Hooks 声明式地使用 setInterval

    2019独角兽企业重金招聘Python工程师标准>>> 本文由云+社区发表 作者:Dan Abramov 接触 React Hooks 一定时间的你,也许会碰到一个神奇的问题: se ...

  9. onclick=两个函数_[译]React函数组件和类组件的差异

    [译]React函数组件和类组件的差异 原文: https://overreacted.io/how-are-function-components-different-from-classes/ 在 ...

最新文章

  1. 及cp含义_当我们谈论CP时,我们在谈论什么?
  2. 【Manning新书】可解释人工智能: 构建可解释机器学习系统
  3. linux ping 报错 sendmsg: Operation not permitted
  4. Matlab功率谱估计
  5. python 浮点数最小值_PYTHON学习笔记(3)——基本数据类型
  6. 【c++ primer读书笔记】【第2章】变量和基本类型
  7. 鸿蒙生态与苹果生态有什么区别,华为想用鸿蒙统一生态,苹果直接用芯片大一统,走到华为前面?...
  8. 使用ajax局部更新Razor页面
  9. ORACLE报错(5)ORA-01102: cannot mount database in EXCLUSIVE mode
  10. 在线Excel转TSV工具
  11. MATLAB关于Mesh的相关命令
  12. oracle mos账号金额,mos账号注正册步骤+证书查询+注意事项.pptx
  13. JavaScript:判断当前浏览器是否为微信浏览器
  14. 找出区间偶数c语言,c语言实践输出某个区间中不是3的倍数的偶数
  15. 金额转换成人民币大写
  16. 计算机03年word做母亲节贺卡,制作图文并茂的作品---用word制作母亲节贺卡PPT课件...
  17. 女孩起名字:诗经中惊艳的女孩名字
  18. 高分卫星影像查询地址
  19. Linux 中断(IRQ/softirq)基础:原理及内核实现
  20. 浅谈计算机领域及职业憧憬

热门文章

  1. 二分法求方程的根_快速求解方程的根——二分法与牛顿迭代法
  2. jQuery:表格的奇偶行变色,jquery实例之表格隔一行
  3. 我感觉这个书上的微信小程序登陆写得不好
  4. Robot Framework-Ride界面介绍及库的添加
  5. TCP 之 RST 原因分析
  6. [转]Design Pattern Interview Questions - Part 2
  7. ASP.NET 文件上传于下载
  8. wxpython 可视化开发pdf_MicroPython for the Internet of Things.pdf
  9. 线程的属性 —— 分离的状态(detached state)、栈地址(stack address)、栈大小(stack size)
  10. mysql 从库 速度太慢_mysql查询速度慢的原因[整理版]