1、前言
我们先来编写一个函数组件:
// src/index
import React from '../react'
function App(props){
return <h1>H1,{props.name}!</h1>
}
const element = (<App name='foo'></App>)
React.render(element, document.getElementById("root"))
函数组件的和标签组件有乱两个不同点:
- 函数组件中的fiber没有DOM节点
- children是通过运行函数得到的而不是props
2、功能实现
2.1 performUnitOfWork添加判断函数组件;
function performUnitOfWork(fiber) {
// 判断是否为函数
const isFunctionComponent =
fiber.type instanceof Function
if (isFunctionComponent) {
updateFunctionComponent(fiber)
} else {
// 更新普通节点
updateHostComponent(fiber)
}
// 省略
}
function updateFunctionComponent(fiber) {
// TODO
}
function updateHostComponent(fiber) {
// TODO
}
2.2 抽离performUnitOfWork中的reconcileChildren方法到updateHostComponent函数;
function updateHostComponent(fiber) {
if (!fiber.dom) {
fiber.dom = createDom(fiber)
}
reconcileChildren(fiber, fiber.props.children)
}
2.3 处理函数组件,执行函数组件来获取children;
/**
* 函数组件处理
* @param {*} fiber
*/
function updateFunctionComponent(fiber) {
const children = [fiber.type(fiber.props)]
reconcileChildren(fiber, children)
}
2.4 接下来我们处理一下没有DOM的fiber;
function commitWork (fiber) {
// 省略
let domParentFiber = fiber.parent
// 一直向上找直到找到有dom的节点
while (!domParentFiber.dom) {
domParentFiber = domParentFiber.parent
}
const domParent = domParentFiber.dom
// 省略
}
2.5 当移除一个节点时,需要不断的向下找,直到找到一个具有 DOM 节点的子节点。
/**
* 处理提交的fiber树
* @param {*} fiber
* @returns
*/
function commitWork(fiber) {
// 省略
// 处理删除节点标记
} else if (fiber.effectTag === "DELETION") {
commitDeletion(fiber, domParent)
}
// 省略
}
/**
* 删除情况下,不断的向下找,直到找到有dom的子节点
* @param {*} fiber
* @param {*} domParent
*/
function commitDeletion(fiber, domParent) {
if (fiber.dom) {
domParent.removeChild(fiber.dom)
} else {
commitDeletion(fiber.child, domParent)
}
}