创建react源码项目-beginWork

96 阅读2分钟

react创建子fiberNode需要当前的current FiberNode和新的reactElement比较创建子fiberNode

  • mount阶段会大量插入节点,性能消耗较大(利用构建离屏操作优化性能
  • update节点只会更新节点,性能消耗较小

创建beginWork

// packages/react-reconciler/src/ReactFiberBeginWork.ts

export const beginWork = (wip: FiberNode) => {
    const tag = wip.tag;
    switch (tag) {
        case HostRoot:
            return updateHostRoot(wip);
        case HostComponent:
            return updateHostComponent(wip);
        case HostText:
                return null;
        default:
            if (__DEV__) {
                    console.warn('beginWork还未实现的类型');
            }
            return null;
    }
};

创建子fiberNode

updateHostRoot 根元素 对应的子fiberNode

const updateHostRoot = (wip: FiberNode) => {
    const baseState = wip.memoizedState;
    const updateQueue = wip.updateQueue as UpdateQueue<Element>;
    const pending = updateQueue.shared.pending; // 新的属性,用于更新赋值
    updateQueue.shared.pending = null; // 新值被使用了,就把新值变成null
    // 开始更新
    const { memoizedState } = processUpdateQueue(baseState, pending);
    wip.memoizedState = memoizedState;

    // 创建子fiberNode
    const nextChildren = wip.memoizedState;
    reconcilerChildren(wip, nextChildren);
    return wip.child;
};

普通元素节点对应的fiberNode

// 元素节点没有更新操作,只生成子fiberNode
function updateHostComponent(wip: FiberNode) {
    const nextProps = wip.pendingProps;
    const nextChildren = nextProps.children;
    reconcilerChildren(wip, nextChildren);
    return wip.child;
}

创建子fiberNode

function reconcilerChildren(wip: FiberNode, children?: ReactElement) {
    const current = wip.alternate;
    if (current !== null) {
        // update
        wip.child = reconcileChildrenFibers(wip, current.child, children);
    } else {
        // mount
        wip.child = mountChildrenFibers(wip, null, children);
    }
}
// /packages/react-reconciler/src/ReactChildFiber.ts
import { ReactElement } from 'shared/ReactTypes';
import { createFiberFromElement, FiberNode } from './ReactFiber';
import { REACT_ELEMENT_TYPE } from 'shared/ReactSymbols';
import { HostText } from './ReactWorkTags';
import { Placement } from './ReactFiberFlags';

function childReconciler(shouldTrackEffects: boolean) {
	function reconcileSingleElement(
		returnFiber: FiberNode,
		currentFiber: FiberNode | null,
		newChild: ReactElement,
	) {
		const fiber = createFiberFromElement(newChild);
		fiber.return = returnFiber;
		return fiber;
	}

	function reconcileSingleTextNode(
		returnFiber: FiberNode,
		currentFiber: FiberNode | null,
		content: string | number,
	) {
		const fiber = new FiberNode(HostText, { content }, null);
		fiber.return = returnFiber;
		return fiber;
	}

	// 定义是否shouldTrackEffects
	function placeSingleChild(fiber: FiberNode) {
		if (shouldTrackEffects && fiber.alternate === null) {
			fiber.flags |= Placement;
		}
		return fiber;
	}

	return function reconcilerChildFibers(
		returnFiber: FiberNode,
		currentFiber: FiberNode | null,
		newChild?: ReactElement,
	) {
            // todo
            // 根据新的reactElement生成fiberNode
            if (typeof newChild === 'object' && newChild !== null) {
                switch (newChild.$$typeof) {
                    case REACT_ELEMENT_TYPE:
                        return placeSingleChild(
                           reconcileSingleElement(returnFiber, currentFiber, newChild),
                        );

                    default:
                        if (__DEV__) {
                            console.warn('未实现的reconcile类型', newChild);
                        }
                        break;
                }
            }

            // HostText
            if (typeof newChild === 'string' || typeof newChild === 'number') {
                    return placeSingleChild(
                        reconcileSingleTextNode(returnFiber, currentFiber, newChild),
                    );
            }

            return null;
    };
}

export const reconcileChildrenFibers = childReconciler(true);
export const mountChildrenFibers = childReconciler(false);

根据ReactElement创建fiberNode


export function createFiberFromElement(element: ReactElement) {
    const { type, key, props } = element;
    let fiberTag: WorkTag = FunctionComponent;
    if (typeof type === 'string') {
            // div type: div
            fiberTag = HostComponent;
    } else if (typeof type !== 'function' && __DEV__) {
            console.warn('未定义的type类型', element);
    }

    const fiber = new FiberNode(fiberTag, props, key);
    fiber.type = type;
    return fiber;
}