一、版本
- react:17.0.2
- react-dom: 17.0.2
二、代码仓库
react源码的管理方式是monorepo模式,它把react中相对独立的模块分割出来作为一个软件包(例如:react包、react-dom包、react-server包等等),将所有软件包统一放置在/packages中,这样一个react代码仓库就包含了所有的react模块。源码地址
三、前置
本次hooks源码阅读,以useState为切入点进行分析。在分析前需要了解一些前置知识点:
(一)ReactElement与fiber
入口函数ReactDom.render,function组件的return、class组件的render,所有采用jsx语法书写的节点,都会被编译器转换,最终以React.createElement()的方式创建出一个对应的ReactElement对象。ReactElement不是一个严格的树,也不是一个严格的链表,在生成过程中是从入口函数ReactDOM.render开始,至顶向下生成的,是所有组件节点的总和。
在ReactElement树(暂且用树表述)和fiber树是以props.children为单位先后交替生成的,ReactElement树构造完毕,fiber树也随后构造完毕。在reconciler阶段会根据ReactElement类型生成对应的fiber节点,但ReactElement与fiber节点并非一一对应,例如Fragement类型的组件在生成fiber节点的时候会被忽略。
import ReactDOM from 'react-dom';
//入口函数
ReactDOM.render(
<App />,
document.getElementById('root')
);
fiber的更新列表中每一个节点中有一个shared属性,该属性指向一个共享更新队列。在class组件中调用setState()时,将会创建新的update对象,并将该update对象添加至当前组件对应fiber节点的shared属性所指向的共享队列中。而对于function组件,为了能够保持function组件的状态,引入了Hook。
(二)fiber与hook
在fiber对象中有一个属性fiber.memoizedState指向fiber节点的内存状态,在function类型组件中,fiber.memoizedState就指向了该function组件的Hook队列。该Hook队列保存了function类型的组件状态。function组件中hook与fiber的关系以及class组件fiber更新队列如下图所示。
四、分析useState
(一)分析fiber与hook如何关联上
useState,useReducer可以在function组件添加内部的state,且useState实际上是useReducer的简易封装,是一个最特殊的useReducer。因此useState,useReducer也称为状态Hook。故此次以useState为分析点进行分析。
对于fiber,class组件、function组件都实现了状态持久化,不同的是class组件是维护fiber.memoizedState;function组件是维护Hook来实现状态持久化。在fiber树构造过程中,不同的fiber类型,只需要调用不同的处理函数来获取fiber子节点。从调用方来讲,只需要调用beginWork(),具体根据不同类型应该调用哪种处理函数则被封装在beginWork函数中,无需关心内部实现。从beginWork函数中我们可以知道function类型调用的是updateFunctionComponent函数,updateFunctionComponent函数内容使用了Hook对象。
在updateFunctionComponent函数中调用了renderWithHooks,至此Fiber与Hook产生了关联。
本次分析源码主要根据第五点的react源码解读系列文章进行学习,从基本概念、运作核心、数据管理等方面依次学习,由于本次项目影响,本次学习计划对hook源码的分析至此,后续将依据此系列文章继续react源码学习。
五、资料分享
在网站查找react-hooks源码解读资料时,发现一个对react源码解读的系列文章,写得很不错,该系列中也有专门针对react-hooks详解。
- [图解React源码系列] https://github.com/7kms/react-illustration-series/tree/v17.0.2
- [hook原理] https://github.com/7kms/react-illustration-series/blob/v17.0.2/docs/main/hook-summary.md