useState & useEffect
/ 6 min read
发现了一个对 React + useState + useHooks
的简单实现:
首先使用 IIFE 来持有两个变量 global
和 index
; 还有三个方法 render
, useState
和 useEffect
.
index
的作用是记录当前的 hooks 数组下标. 当使用 useState
或者 useEffect
时候进行移位.
在 render
方法中, 需要将 index
重置为 0, 不管是第一次 render 还是状态变化导致的 rerender.
useState
里面初始化了 hooks
数组, 当第一次 render, 会将初始的 state
存放到 hooks
数组内, 然后 index++
. 如果是 rerender, 则取出 hooks
内的数据(缓存).
有趣的是 setState
方法, 它使用 IIFE 来记录了当前 state
所在 hooks
的下标 index
, 然后是对 hooks
之前的旧变量进行覆盖, 最后再调用 render
方法进行 rerender.
useEffect
也是比较有趣, 它也是利用的 hooks
数组, 当第一次调用, 也就是第一次 render 时候, hooks
当前 index
数据为空, 所以第一次 render 必定会执行回调函数. 然后将 deps
存入到 hooks[index]
, 这样不管是哪次 render 都是记录了上一次的数据. 当 deps
是个空数组时, if
内的 some
永远是 false
, 所以就达成了: 空数组代表着 componentDidMount
. 当非首次 render时, 要进行判断:
传入的 deps
的每个元素, 是否在 oldDeps
下有变化, 如果有变化, 则需要执行回调.
useEffect
使用了 hooks
而且可以多次调用 useEffect
所以到最后也需要将 index++
.
这样, 不管是第一次 render 还是第 n 次 render, 都是顺序使用的 index
, hooks
都不会乱, 正式因为这个原因:
Don’t call Hooks inside loops, conditions, or nested functions.
这个实现的不足点
- 只能 render 一个 Component, 因为此实现里的 React 只有一个
global
和 index
, 如果存在多个 Component
, 则共用同一份数据, 则会出错.
deps.some((d, index) => !Object.is(d, oldDeps[index]))
这样写, 逻辑比较混乱.
- BUG: 当 Component 不使用
useState
而使用 useEffect
, 或者 useEffect
在 useState
前使用, 则 hooks
不会被初始化而报错.
useEffect
并不是每次 render 后执行回调, 而是立即调用.
自己实现了一个简易的 useState