Hook实现原理

董俊豪
2022-02-25 / 0 评论 / 0 点赞 / 509 阅读 / 1,824 字
温馨提示:
本文最后更新于 2022-02-28,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

ReactHook.js dispatcher调度
1.当调用useXXX时,通过resolveDispatcher()这个方法生成一个调度器dispatcher
2.当调用 resolveDispatcher()获取调度器时,实际调用了./ReactCurrentDispatcher.js 里的dispactcher.useState()
3.import type 只是一个类型检查工具,针对.js文件中的代码进行数据类型检查,从另一个模块中导入数据类型 ReactFiberHooks.js 所有官方提供的Hook源码在这里面

Hook的实现
每一个Hook都有两个相关函数:mountXXX()和updateXXX() 它们分别在Mount阶段(挂载 初始化 第一次执行useXXX()) Update阶段(组件更新 重新渲染)
UseState 在Mount阶段所做的工作是:
1.获取当前Hook节点,同时将当前Hook添加到Hook链表中
2.初始化Hook的状态,即读取初始state值
3.创建一个新的链表作为更新队列,用来存放更新操作(setXxx())
4.创建一个dispatch方法(即useState 返回的数组第二个参数setXxx()),该方法用来修改state
5.返回当前state和修改state的方法(dispatch)

存储Hook的数据结构--链表
链表中每个节点就是一个Hook,如果
useEffect Hook指向最新的正在执行的Hook

Update阶段 执行useState所做的事情是:
1.获取正在执行的处于更新阶段Hook节点
2.获取该Hook节点的更新队列链表
3.从该更新队列的最早的update对象节点开始遍历 一直遍历到最近添加的update对象节点
4.当遍历完最近的一个update对象节点后,此时newState里存放的就是最新值,最后返回newState,用户拿到最新的state

总结useState整体运行流程
第一次执行useState 也就是mount阶段,执行mountState
1.在Hook链表添加该useState的Hook节点(Hook链表添加Hook节点)
2.初始化state的值
3.返回此次渲染的state和修改state的方法
当调用setXxx/dispatchAction时
1.创建update对象,并将update对象添加到该Hook节点的更新队列链表
2.判断传入的值(action)和当前正在屏幕上渲染的state值是否相同,若相同则略过,若不同则调用scheduleWork安排组件重新渲染
3.当前所有setXxx都逐一执行完后,假如其中能满足2的条件 则处罚更新进入Update阶段
组件重新渲染(更新时)
1.获取该useState Hook的更新队列链表
2.遍历这个更新队列链表,从最早的那一个update对象进行遍历,直到便利到最近的添加的那一个update对象,最后得到最新state返回
3.返回此次渲染的state和修改state的方法
初次渲染执行mountXxx() 重新渲染执行updateXxx(),useEffect同理 对应也有mountEffect和updateEffect

useEffect在mount阶段主要做的事情
1.获取当前Hook节点,并把它添加到Hook链表中
2.获取本次effect的deps依赖
3.将effect添加到fiberNode 的updateQuenu中,updateQuenue的lastEffect 属性指向的始终是最新添加进队列的effect,lastEffect的next始终指向最早添加进来的effect

useEffect在Update阶段主要做的事情
1.获取当前Hook节点,并把它添加到Hook链表中;
2.获取本次effect的deps依赖
3.拿本次effect的依赖和上一次渲染时的effect的依赖做对比
假如没有依赖发生改变,那么就只给这次effect打上HookPassive的tag,在commit阶段,跳过这一次effect的执行
假如依赖发生改变,那么就会给这次effect打上HookPassive和HookHasEffect两个tag,在commit阶段(组件视图渲染完成后),执行这一次effect
4.将本次effect添加到fiberNode的updateQuenue中,并将本次effect保存在当前Hook节点的memoizedState属性中

0

评论区