源地址/
双向链表
学习JavaScript数据结构与算法
链表
学习JavaScript数据结构与算法
队列
学习JavaScript数据结构与算法
栈
学习JavaScript数据结构与算法
数组
学习JavaScript数据结构与算法
模板
####
js的==和===转换
附加一段文章摘要,字数最好在140字以内,会出现在meta的description里面
hexo多台电脑使用
来自 https://juejin.im/post/5acf22e6f265da23994eeac9 还有 https://www.zhihu.com/question/21193762
hook原理
hoos使用可能产生的疑惑
为什么 useEffect 第二个参数是空数组,就相当于 ComponentDidMount ,只会执行一次?
为什么只能在函数的最外层调用 Hook,不能在循环、条件判断或者子函数中调用?
自定义的 Hook 是如何影响使用它的函数组件的?
Capture Value 特性是如何产生的?
带着疑惑往下看
useState
最简单的 useState 用法是这样的:
1 | function Counter() { |
基于 useState 的用法, 我们尝试着自己实现一个 useState
1 | function useState(initialValue) { |
这时我们发现,点击 Button 的时候,count 并不会变化。
为什么呢?我们没有存储 state,每次渲染 Counter 组件的时候,state 都是新重置的。
自然我们就能想到,把 state 提取出来,存在 useState 外面。
1 | var _state; // 把 state 存储在外面 |
重新渲染组件的时候会读取全局对象的值,拿到的就是最新值了
useEffect
useEffect 是另外一个基础的 Hook,用来处理副作用,最简单的用法是这样的:
1 | useEffect(() => { |
我们知道 useEffect 有几个特点:
有两个参数
callback和dependencies数组如果 dependencies 不存在,那么 callback 每次 render 都会执行
如果 dependencies 存在,只有当它
发生了变化, callback 才会执行
实现一个 useEffect:
1 | let _deps; // _deps 记录 useEffect 上一次的 依赖 |
到这里,我们又实现了一个可以工作的 useEffect,似乎没有那么难。
此时我们应该可以解答一个问题:
为什么第二个参数是空数组,相当于 componentDidMount ?
因为依赖一直不变化,callback 不会二次执行。
Hooks 的复用问题
到现在为止,我们已经实现了可以工作的 useState 和 useEffect。
但是有一个很大的问题:它俩都只能使用一次,因为只有一个 _state 和 一个 _deps。
比如
1 | const [count, setCount] = useState(0); |
count 和 username 永远是相等的,因为他们共用了一个 _state,并没有地方能分别存储两个值。
我们需要可以存储多个 _state 和 _deps。
如 《React Hooks: not magic, just arrays》所写,我们可以使用数组,来解决 Hooks 的复用问题。
代码关键在于:
初次渲染的时候,按照 useState,useEffect 的顺序,把 state,deps 等按顺序塞到 memoizedState 数组中。
更新的时候,按照顺序,从 memoizedState 中把上次记录的值拿出来。
1 |
|
图片解读
如果还是不清楚,可以看下面的图。
我们用图来描述 memoizedState 及 cursor 变化的过程。
1. 初始化
2. 初次渲染
3. 事件触发
4. Re-Render
到这里,我们实现了一个可以任意复用的 useState 和 useEffect。
理解:useState存的是值 useEffect存的是依赖,setState的时候改变的是闭包缓存的那个下标的memoizedState的值, 然后下标会重置为0并且组件会重新执行走一遍。一直改变的是memoizedState,而hooks只是函数会重新执行。
同时,也可以解答几个问题:
Q:为什么只能在函数最外层调用 Hook?为什么不要在循环、条件判断或者子函数中调用?
A:memoizedState 数组是按hook定义的顺序来放置数据的,如果 hook 顺序变化,memoizedState 并不会感知到。
Q:自定义的 Hook 是如何影响使用它的函数组件的?
A:共享同一个 memoizedState,共享同一个顺序。
Q:”Capture Value” 特性是如何产生的?
A:每一次 ReRender 的时候,都是重新去执行函数组件了,对于之前已经执行过的函数组件,并不会做任何操作。
真正的 React 实现
虽然我们用数组基本实现了一个可用的 Hooks,了解了 Hooks 的原理,但在 React 中,实现方式却有一些差异的。
React 中是通过类似单链表的形式来代替数组的。
通过 next 按顺序串联所有的 hook。
1 | type Hooks = { |
memoizedState,cursor 是存在哪里的?
如何和每个函数组件一一对应的?
我们知道,react 会生成一棵组件树(或Fiber 单链表),树中每个节点对应了一个组件。
hooks 的数据就作为组件的一个信息,存储在这些节点上,伴随组件一起出生,一起死亡。