[路飞]- mini-react之渲染函数组件 类组件 文本节点 fragment节点

183 阅读2分钟

「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战

代码地址 分支2.0

读完本篇文章我们要了解react 如何渲染函数组 类组件 文本节点 fragment节点

效果如下:

image.png

在仓库的1.0分支上继续进行开发:

1. 实现函数组件和类组件

为什么这里将函数组件和类组件一起拿出来, 因为他们的type类型都是function

类型相同的话如何区分开来呢?源码里给类组件的type原型上添加了一个标记叫isReactComponent

首先我们在demomain.jsx写上一个函数组件和一个类组件。

src\ReactFiberWorkLoop.jsperformUnitOfWork()方法上做一个优化,根据fiber的tag值做不同的处理,在src\ReactFiber.js里给tag根据type给fiber.tag做标记,这里还维护了一个全局的tagsrc\ReactWorkTag.js,首先判断type如果是一个函数的话,然后作进一步判断type.prototype.isReactComponent存在,则tagClassComponent否则为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. 文本节点

这里可以观察到文本节点被转换的vnodetypeundefined, 文本节点没有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如何做任务调度的