React 运行时
React.render(<App />, div)
- 创建fiberRoot 和 rootFiber
rootFiber 作为fiber树的根节点,它的处理是具有特殊性的
// 这个函数功能就是一句话:根据组件的类型做不同的渲染处理
function beginWork(current, workInProgress, renderLanes) {
// 跳过更新的条件(是否存在过期时间<执行了setState会生成> 新旧props ===)
case FunctionComponent:
case ClassComponent:
case HostRoot:
case HostComponent:
case ForwardRef:
case Fragment:
case ContextProvider:
case ContextConsumer:
}
对 rootFiber 的处理
function updateHostRoot(current, workInProgress, renderLanes) {
// 1. rootFiber 的children其实就是 <App />,关于标签的本质,在我之前的文章有描述;
// 2. reconcileChildren(current, workInProgress, nextChildren) 解析children
// 3. 返回的 child(已经被reconcileChildren处理成fiber对象)
// 继续做beginwork根据组件类型渲染,其实是一个递归的过程;
return workInProgress.child;
}
reconcileChildren 做了些啥?
function reconcileChildren(returnFiber, currentFirstChild, newChild) {
// 这里分成3个部分
// 1. 如果是普通的 REACT_ELEMENT_TYPE 组件,直接返回fiber对象,这个fiber对象的创建依据如下:
// 根据被babel编译的标签返回的对象;
// 复用上一次的fiber(这个发生在更新阶段),复用组件上次的状态, 但会传入pendingprops(因为每次标签都会执行 React.createElement);
// 复用的条件:
// - key;
// - type(elementType) 这个其实就是你定义的组件, 需要 === 才能判断一致;
// 在函数组件里 const 一个组件,这个时候注意了,在你每次更新进来时,都会重新 const 新的组件,会影响diff和组件的复用,建议组件抽到外面去;
// 2. diff
// newChild.type === REACT_FRAGMENT_TYPE <></>
// newChild = newChild.props.children
// reconcileChildrenArray, diff过程
// 3. 删除多余的组件
return deleteRemainingChildren(returnFiber, currentFirstChild);
}
直到遍历到单侧最底, 又开始从底向上遍历
function completeUnitOfWork(unitOfWork) {
// 对于底层组件
// 1. 如果是 hostComponent 即原生浏览器标签, 创建dom,css属性添加,事件绑定
// 2. appendChild 子节点
// 2. 组件的 context 的pop(维护context, 使每个组件只能使用祖先的context)
// 4. 向上遍历并传递副作用(effect)
// 5. 如果这个fiber存在sibling,会继续beginWork递归操作
}
最终所有副作用都在root上;
此时,dom都渲染了,开始执行这些副作用;
dom更新或者删除,生命周期