例子:
import React, { useState, useEffect } from "React";
import "./App.css";
function App() {
const [num, setNum] = useState(0);
const handleClick = () => {
setNum(num + 1);
};
return (
<div onClick={handleClick} className="parentDiv">
<code key="child" title={num}>
{num}
</code>
</div>
);
}
fiber是根据什么构建的?
我们来阅读react的源码: 首先在这里打上断点,因为无论如何,只要新建fiber节点,都要通过这个函数
发现fiber节点是根据value构建的
而value又是根据 value = renderWithHooks(null, workInProgress, Component, props, context, renderLanes)构建的,最后发现renderWithHook其实调用了
var children = Component(props, secondArg);,Component其实调用了我们使用的例子,最终结论就是fiber是根据jsx形成的虚拟dom构建的,这其实也是合理的。
我们在 root.current = finishedWork;打上断点发现fiber树和真实的dom结构很类似,区别就是有些节点有fiber而没有真实dom对应。
fiber结构
function FiberNode(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
// 作为静态数据结构的属性
this.tag = tag;
this.key = key;
this.elementType = null;
this.type = null;
this.stateNode = null;
// 用于连接其他Fiber节点形成Fiber树
this.return = null;
this.child = null;
this.sibling = null;
this.index = 0;
this.ref = null;
// 作为动态的工作单元的属性
this.pendingProps = pendingProps;
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
this.dependencies = null;
this.mode = mode;
this.effectTag = NoEffect;
this.nextEffect = null;
this.firstEffect = null;
this.lastEffect = null;
// 调度优先级相关
this.lanes = NoLanes;
this.childLanes = NoLanes;
// 指向该fiber在另一次更新时对应的fiber
this.alternate = null;
}
其中child,return和sibling用来搭建fiber树的
var created = createFiberFromFragment(element.props.children, returnFiber.mode, lanes, element.key);
created.return = returnFiber;
workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderLanes);
pendingProps 表示本次需要的更新属性 memoizedProps上一次的属性
var oldProps = current.memoizedProps;
var newProps = workInProgress.pendingProps;
var updatePayload = prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, currentHostContext);
workInProgress.updateQueue = updatePayload;
updateQueue 在commit阶段通过updateProperty更新真实的dom
workInProgress.updateQueue = updatePayload;
var updatePayload = finishedWork.updateQueue;
finishedWork.updateQueue = null;
if (updatePayload !== null) {
commitUpdate(instance, updatePayload, type, oldProps, newProps);
}
初始化render commit各个阶段做了什么
首先创建fiberRoot 和 rootFiber
function createFiberRoot(containerInfo, tag, hydrate, hydrationCallbacks) {
var root = new FiberRootNode(containerInfo, tag, hydrate);
// stateNode is any.
var uninitializedFiber = createHostRootFiber(tag);
root.current = uninitializedFiber;
uninitializedFiber.stateNode = root;
initializeUpdateQueue(uninitializedFiber);
return root;
}
创建整个fiber树
生成真实的dom节点
var instance = createInstance(type, newProps, rootContainerInstance, currentHostContext, workInProgress);
appendAllChildren(instance, workInProgress, false, false);
workInProgress.stateNode = instance; // Certain renderers require commit-time effects for initial mount.
// (eg DOM renderer supports auto-focus for certain elements).
// Make sure such renderers get scheduled for later work.
if (finalizeInitialChildren(instance, type, newProps, rootContainerInstance)) {
markUpdate(workInProgress);
}
渲染到页面 在commit阶段
if (isContainer) {
insertOrAppendPlacementNodeIntoContainer(finishedWork, before, parent);
} else {
insertOrAppendPlacementNode(finishedWork, before, parent);
}
在beginWork阶段中的 reconcileChildFibers 添加了placement标记