「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」
代码地址 分支2.0
读完本篇文章我们要了解react 如何渲染函数组 类组件 文本节点 fragment节点
效果如下:
在仓库的1.0分支上继续进行开发:
1. 实现函数组件和类组件
为什么这里将函数组件和类组件一起拿出来, 因为他们的
type类型都是function
类型相同的话如何区分开来呢?源码里给类组件的type原型上添加了一个标记叫
isReactComponent
首先我们在demo的main.jsx写上一个函数组件和一个类组件。
在src\ReactFiberWorkLoop.js的performUnitOfWork()方法上做一个优化,根据fiber的tag值做不同的处理,在src\ReactFiber.js里给tag根据type给fiber.tag做标记,这里还维护了一个全局的tagsrc\ReactWorkTag.js,首先判断type如果是一个函数的话,然后作进一步判断type.prototype.isReactComponent存在,则tag为ClassComponent否则为FunctionComponent
维护好了tag后,我们开始对函数组件做处理
函数组件
函数组件的孩子节点就是type执行后的结果,在执行的时候并把props参数传入。
在src\ReactFiberReconciler.js
function updateFunctionComponent(wip){
const {type, props} = wip
const children = type(props)
reconcilerChildren(wip, children)
}
接着我们处理类组件
类组件
类组件不一样,它需要实例化,它的孩子节点是render执行后的结果
function updateClassComponent(wip){
const {type, props} = wip
const instance = new type(props)
const children = instance.render()
reconcilerChildren(wip, children)
}
多一步处理,在类组件声明的时候class ClassComponent extends Component
这里需要对Component进行处理
function Component(props){
this.props = props // props是从这里做了存储 所以可以直接在类组件使用props
}
Component.prototype.isReactComponent = {} // 区分函数组件
2. 文本节点
这里可以观察到文本节点被转换的vnode的type是undefined, 文本节点没有children 这里为了统一构造一个children,
fiber.tag = HostText
fiber.props = {children: vnode}
function updateTextComponent(wip){
wip.stateNode = document.createTextNode(wip.props.children)
}
3. fragment节点
fragment节点是没有父节点的所以直接协调子节点就行了
function updateFragmentComponent(wip){
reconcilerChildren(wip, wip.props.children)
}
还有一个优化:
src\ReactFiberWorkLoop.js
我们之前在commitWorker()方法里的parentNode写死了,如果是函数组件,它的父节点是没有stateNode的,所以我们需要递归向上找父原生节点
function getParentNode(wip){
let parent = wip
while(parent){
if(parent.stateNode){
return parentStateNode
}
parent = parent.return
}
}
好了 我们以上就实现了函数组件 类组件 文本节点 fragment节点的渲染。
接下来我们看看react如何做任务调度的