React19源碼系列之渲染階段performUnitOfWork

在 React 內部實現中,將 render 函數分為兩個階段:

  1. 渲染階段
  2. 提交階段

其中渲染階段可以分為 beginWork 和 completeWork 兩個階段,而提交階段對應著 commitWork。

在之前的root.render過程中,渲染過程無論是并發模式執行還是同步模式執行,都是執行到函數performUnitOfWork,所以,這次,具體看看performUnitOfWork函數的執行過程。

workLoopSync

performUnitOfWork

performUnitOfWork 函數的主要作用是執行單個 Fiber 節點的工作單元。該函數會根據當前 Fiber 節點的狀態,調用 beginWork 函數開始處理這個 Fiber 節點,并根據處理結果決定是繼續處理下一個 Fiber 節點,還是完成當前 Fiber 節點的工作。

函數參數含義

  • unitOfWork:類型為 Fiber,表示當前要處理的 Fiber 節點,也就是當前的工作單元。

function performUnitOfWork(unitOfWork: Fiber): void {// unitOfWork.alternate 指向當前 Fiber 節點的替代節點。在 React 的協調過程中,每個 Fiber 節點都有一個對應的替代節點,用于在雙緩沖機制中存儲舊的狀態。這里將其賦值給 current。const current = unitOfWork.alternate;// next:用于存儲 beginWork 函數返回的下一個要處理的 Fiber 節點。let next;// 調用 beginWork 函數開始處理當前 Fiber 節點,傳入當前 Fiber 節點的替代節點 current、當前 Fiber 節點 unitOfWork 以及相關的渲染車道 entangledRenderLanes。beginWork 函數會根據 Fiber 節點的類型和狀態,執行相應的工作,如創建新的 Fiber 節點、更新已有 Fiber 節點等,并返回下一個要處理的 Fiber 節點。next = beginWork(current, unitOfWork, entangledRenderLanes);// 將 unitOfWork 的 pendingProps(待處理的屬性)賦值給 memoizedProps(記憶化的屬性)。這意味著當前 Fiber 節點的屬性已經被處理并確定下來。unitOfWork.memoizedProps = unitOfWork.pendingProps;// 如果 next 為 null,說明 beginWork 函數沒有返回下一個要處理的 Fiber 節點,即當前 Fiber 節點的工作沒有產生新的工作。if (next === null) {// If this doesn't spawn new work, complete the current work.// 調用 completeUnitOfWork 函數完成當前 Fiber 節點的工作,可能會進行一些清理和提交操作。completeUnitOfWork(unitOfWork);} else {// 如果 next 不為 null,將 next 賦值給 workInProgress,表示下一個要處理的 Fiber 節點成為當前的工作進行中的節點,后續將繼續處理這個節點。workInProgress = next;}
}

渲染階段一beginWork

beginWork 函數的主要任務是根據不同的 Fiber 節點類型和更新情況,對當前 Fiber 節點進行處理,決定是復用舊的 Fiber 節點,還是創建新的子 Fiber 節點。該函數會根據 Fiber 節點的 tag 屬性(表示節點類型),調用不同的處理函數來更新或掛載節點。

beginWork 函數接收三個參數:

  • current:舊的 Fiber 節點,若為 null 則表示沒有舊節點。
  • workInProgress:新的 Fiber 節點,也就是要進行處理的節點。
  • renderLanes:渲染優先級車道,用于標識當前渲染任務的優先級。
    function beginWork(current: Fiber | null,workInProgress: Fiber,renderLanes: Lanes,
    ): Fiber | null {// 有舊節點,非首次渲染if (current !== null) {// current.memoizedProps 存儲了舊 Fiber 節點上一次渲染時使用的屬性。const oldProps = current.memoizedProps;// workInProgress.pendingProps 存儲了新 Fiber 節點即將使用的屬性。const newProps = workInProgress.pendingProps;if (oldProps !== newProps ||hasLegacyContextChanged() )) {didReceiveUpdate = true;} else {const hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(current,renderLanes,);// 嘗試提前退出渲染流程if (!hasScheduledUpdateOrContext &&(workInProgress.flags & DidCapture) === NoFlags) {// No pending updates or context. Bail out now.didReceiveUpdate = false;return attemptEarlyBailoutIfNoScheduledUpdate(current,workInProgress,renderLanes,);}if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {didReceiveUpdate = true;} else {didReceiveUpdate = false;}}} else {// 首次渲染時,將 didReceiveUpdate 標記為 false。didReceiveUpdate = false;}// 將 workInProgress.lanes 設置為 NoLanes 時,意味著當前 Fiber 節點沒有需要處理的更新任務,或者更新任務已經處理完畢。// 會清除當前 workInProgress Fiber 節點上的所有更新標記。workInProgress.lanes = NoLanes;switch (workInProgress.tag) {// 省略代碼。。。case Throw: {// This represents a Component that threw in the reconciliation phase.// So we'll rethrow here. This might be a Thenable.throw workInProgress.pendingProps;}}}

    ?<Tag>FunctionComponent(常量為0)

    負責解析函數組件的 props,并調用 updateFunctionComponent 執行組件的實際渲染。主要工作包括:

    1. 獲取組件類型和待處理的 props。
    2. 解析默認 props(針對非類組件)。
    3. 調用函數組件的更新邏輯。
    case FunctionComponent: {// fiber的組件類型const Component = workInProgress.type;// 待處理propsconst unresolvedProps = workInProgress.pendingProps;const resolvedProps =disableDefaultPropsExceptForClasses ||workInProgress.elementType === Component? unresolvedProps: resolveDefaultPropsOnNonClassComponent(Component, unresolvedProps);return updateFunctionComponent(current,// 表示當前的 Fiber 節點workInProgress,// 正在處理的fiberComponent,// 函數組件resolvedProps,// 解析后的屬性propsrenderLanes,// 渲染優先級車道);
    }

    updateFunctionComponent?

    updateFunctionComponent?函數負責執行函數組件,處理 Hooks,并根據返回的 JSX 內容生成新的子 Fiber 節點。該函數實現了函數組件的渲染邏輯、狀態管理以及性能優化(如 bailout 機制)。?

    function updateFunctionComponent(current: null | Fiber,workInProgress: Fiber,Component: any,nextProps: any,renderLanes: Lanes,
    ) {let context;if (!disableLegacyContext && !disableLegacyContextForFunctionComponents) {//   // 未屏蔽的上下文const unmaskedContext = getUnmaskedContext(workInProgress, Component, true);// 經過屏蔽的上下文context = getMaskedContext(workInProgress, unmaskedContext);}let nextChildren;let hasId;prepareToReadContext(workInProgress, renderLanes);// 執行hooksnextChildren = renderWithHooks(current,workInProgress,Component,nextProps,context,renderLanes,);// 表示組件沒有接收到新的更新。if (current !== null && !didReceiveUpdate) {// bailoutHooks 會跳過 Hooks 的更新bailoutHooks(current, workInProgress, renderLanes);// 直接復用之前的結果。return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);}// React DevTools reads this flag.// 標記已完成workInProgress.flags |= PerformedWork;//reconcileChildren 函數用于對比新舊子節點,生成新的 Fiber 樹結構。reconcileChildren(current, workInProgress, nextChildren, renderLanes);return workInProgress.child;
    }

    工具函數之 resolveDefaultPropsOnNonClassComponent

    resolveDefaultPropsOnNonClassComponent 是 React 中用于處理非類組件(如函數組件)默認 props 的函數。它會將組件定義的 defaultProps 對象與實際傳入的 props 合并,確保未顯式提供的 props 使用默認值。

    函數參數含義

    • Component:組件本身(函數或類)。
    • baseProps:實際傳入的 props 對象。
      function resolveDefaultPropsOnNonClassComponent(Component: any,baseProps: Object,
      ): Object {// 若啟用則僅對類組件保留默認 props 支持,函數組件將完全忽略 defaultProps。if (disableDefaultPropsExceptForClasses) {// Support for defaultProps is removed in React 19 for all types// except classes.return baseProps;}// 合并默認 propsif (Component && Component.defaultProps) {// Resolve default props. Taken from ReactElementconst props = assign({}, baseProps);const defaultProps = Component.defaultProps;for (const propName in defaultProps) {if (props[propName] === undefined) {props[propName] = defaultProps[propName];}}return props;}return baseProps;
      }

      工具函數之?bailoutHooks

      bailoutHooks?函數用于在組件無需重新渲染時跳過 Hooks 的更新。當組件的 props、context 或狀態沒有變化時,React 會觸發 bailout 邏輯,直接復用之前的渲染結果,從而避免不必要的計算和副作用執行。

       function bailoutHooks(current: Fiber,workInProgress: Fiber,lanes: Lanes,
      ): void {// 復用 Hooks 更新隊列workInProgress.updateQueue = current.updateQueue;// 清除副作用// PassiveEffect:表示存在需要異步執行的副作用(如 useEffect)。
      // UpdateEffect:表示存在需要同步執行的副作用(如 useLayoutEffect)。workInProgress.flags &= ~(PassiveEffect | UpdateEffect);// 從當前 Fiber 的 lanes 中移除本次渲染的優先級,表示該優先級的更新已處理完畢。current.lanes = removeLanes(current.lanes, lanes);
      }

      bailout 機制通常在以下情況觸發:

      1. props 未變化:前后 props 對象通過淺比較(Object.is)相等。
      2. context 未變化:組件依賴的上下文值沒有更新。
      3. 被 React.memo 包裹:函數組件被 React.memo 高階組件包裹,且 props 未變化。
      4. 無狀態更新:組件內部狀態沒有變化。

      工具函數之?bailoutOnAlreadyFinishedWork

      bailoutOnAlreadyFinishedWork?函數用于在組件無需重新渲染時直接復用現有 Fiber 樹結構。當組件的 props、狀態或上下文沒有變化時,React 會觸發 bailout 邏輯,跳過該組件及其子樹的協調過程,直接復用之前的渲染結果,從而顯著提升性能。

      function bailoutOnAlreadyFinishedWork(current: Fiber | null,workInProgress: Fiber,renderLanes: Lanes,
      ): Fiber | null {if (current !== null) {// 直接將當前 Fiber 的依賴信息復制到新 Fiber,避免重新收集依賴。workInProgress.dependencies = current.dependencies;}// 標記跳過的更新優先級markSkippedUpdateLanes(workInProgress.lanes);// Check if the children have any pending work.if (!includesSomeLane(renderLanes, workInProgress.childLanes)) {// 啟用延遲上下文傳播的if (enableLazyContextPropagation && current !== null) {lazilyPropagateParentContextChanges(current, workInProgress, renderLanes);if (!includesSomeLane(renderLanes, workInProgress.childLanes)) {return null;}} else {return null;}}// 克隆子節點cloneChildFibers(current, workInProgress);return workInProgress.child;
      }
      

      ?工具函數之?markSkippedUpdateLanes

      markSkippedUpdateLanes?是 React 性能監控系統中的關鍵函數,用于記錄被跳過的更新優先級。當組件由于 bailout 機制(如 props 未變化)而跳過渲染時,React 使用該函數標記這些被跳過的優先級

      function markSkippedUpdateLanes(lane: Lane | Lanes): void {workInProgressRootSkippedLanes = mergeLanes(lane,workInProgressRootSkippedLanes,);
      }let workInProgressRootSkippedLanes: Lanes = NoLanes;

      工具函數之?includesSomeLane

      includesSomeLane?函數用于判斷兩個優先級集合(Lanes)是否存在交集。

      function includesSomeLane(a: Lanes | Lane, b: Lanes | Lane): boolean {return (a & b) !== NoLanes;
      }

      工具函數之 cloneChildFibers

      cloneChildFibers?函數用于在組件 bailout(跳過渲染)時淺克隆子 Fiber 節點。當父組件因 props 未變化而無需重新渲染時,React 會復用子 Fiber 結構,通過克隆操作創建新的 workInProgress 樹,避免重新協調整個子樹,從而顯著提升性能。

      function cloneChildFibers(current: Fiber | null,workInProgress: Fiber,
      ): void {// 若 current 存在且子節點已變化,拋出錯誤if (current !== null && workInProgress.child !== current.child) {throw new Error('Resuming work not yet implemented.');}if (workInProgress.child === null) {return;}// 克隆首個子節點let currentChild = workInProgress.child;let newChild = createWorkInProgress(currentChild, currentChild.pendingProps);workInProgress.child = newChild;newChild.return = workInProgress;// 循環克隆所有兄弟節點while (currentChild.sibling !== null) {currentChild = currentChild.sibling;newChild = newChild.sibling = createWorkInProgress(currentChild,currentChild.pendingProps,);newChild.return = workInProgress;}// 最后一個節點的 sibling 設為 null,確保鏈表正確結束。newChild.sibling = null;
      }

      工具函數之 prepareToReadContext

      prepareToReadContext 函數是 React 渲染流程中的關鍵環節,用于為當前 Fiber 節點準備上下文讀取環境。它主要完成以下工作:

      1. 設置當前渲染的 Fiber 節點。
      2. 重置上下文依賴鏈表。
      3. 處理上下文更新標記,確保依賴的上下文變化能觸發組件重新渲染。
      function prepareToReadContext(workInProgress: Fiber,renderLanes: Lanes,
      ): void {// currentlyRenderingFiber:全局變量,指向當前正在渲染的 Fiber 節點。
      // lastContextDependency:全局變量,用于構建上下文依賴鏈表,初始化為 null。currentlyRenderingFiber = workInProgress;lastContextDependency = null;const dependencies = workInProgress.dependencies;if (dependencies !== null) {if (enableLazyContextPropagation) {// Reset the work-in-progress list// 重置依賴鏈表(延遲傳播模式)dependencies.firstContext = null;} else {const firstContext = dependencies.firstContext;if (firstContext !== null) {if (includesSomeLane(dependencies.lanes, renderLanes)) {// Context list has a pending update. Mark that this fiber performed work.// 上下文有更新,標記當前 Fiber 執行了工作markWorkInProgressReceivedUpdate();}// Reset the work-in-progress listdependencies.firstContext = null;}}}
      }

      ?<Tag>HostRoot

      case HostRoot:return updateHostRoot(current, workInProgress, renderLanes);

      工具函數之 updateHostRoot

      updateHostRoot 是 React 渲染流程中處理根組件(HostRoot Fiber)的核心函數,負責協調根組件的更新邏輯,包括狀態處理、子節點 reconciliation、服務端渲染水合(Hydration)等。

      function updateHostRoot(current: null | Fiber,workInProgress: Fiber,renderLanes: Lanes,
      ) {// 推入根組件的上下文,確保子組件能訪問正確的根狀態。// pushHostRootContext(workInProgress);if (current === null) {throw new Error('Should have a current fiber. This is a bug in React.');}// 獲取新 props 和舊狀態const nextProps = workInProgress.pendingProps;const prevState = workInProgress.memoizedState;const prevChildren = prevState.element;// 復制當前更新隊列到新的 workInProgress Fiber,確保更新操作的不可變性。cloneUpdateQueue(current, workInProgress);// 計算新的根狀態(nextState),處理狀態更新(如 setState)和副作用。processUpdateQueue(workInProgress, nextProps, null, renderLanes);const nextState: RootState = workInProgress.memoizedState;const root: FiberRoot = workInProgress.stateNode;// pushRootTransition(workInProgress, root, renderLanes);// suspendIfUpdateReadFromEntangledAsyncAction();const nextChildren = nextState.element;if (supportsHydration && prevState.isDehydrated) {} else {// resetHydrationState();// 若新子節點與舊子節點相同,通過 bailout 跳過調和過程,直接復用現有 Fiber。if (nextChildren === prevChildren) {return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);}// 當子節點變化時,通過 reconcileChildren 生成新的子 Fiber 樹,進入 diff 流程。reconcileChildren(current, workInProgress, nextChildren, renderLanes);}return workInProgress.child;
      }

      工具函數之 cloneUpdateQueue

      cloneUpdateQueue 是 React 內部用于克隆更新隊列(Update Queue)的核心函數,主要作用是在調和(Reconciliation)階段為 workInProgress Fiber 創建當前 Fiber(current)的更新隊列副本。

      function cloneUpdateQueue<State>(current: Fiber,workInProgress: Fiber,
      ): void {// Clone the update queue from current. Unless it's already a clone.const queue: UpdateQueue<State> = (workInProgress.updateQueue: any);const currentQueue: UpdateQueue<State> = (current.updateQueue: any);// 僅當新舊隊列引用相同時才執行克隆(避免重復克隆)if (queue === currentQueue) {const clone: UpdateQueue<State> = {baseState: currentQueue.baseState,firstBaseUpdate: currentQueue.firstBaseUpdate,lastBaseUpdate: currentQueue.lastBaseUpdate,shared: currentQueue.shared,callbacks: null, // 重置回調,避免舊回調影響新 Fiber};workInProgress.updateQueue = clone;}
      }
      interface UpdateQueue<State> {baseState: State;                // 基礎狀態(未處理更新的狀態)firstBaseUpdate: Update<State>;  // 第一個未處理的更新lastBaseUpdate: Update<State>;   // 最后一個未處理的更新shared: { [key: string]: mixed }; // 共享狀態(如上下文)callbacks: Callback | null;      // 更新回調函數
      }

      工具函數之 processUpdateQueue

      processUpdateQueue函數的核心作用是將組件的狀態更新隊列(queue)中的更新合并到當前狀態(inst.state),確保狀態按順序更新,并處理函數式更新和對象合并邏輯。

      function processUpdateQueue(internalInstance: InternalInstance,inst: any,props: any,maskedLegacyContext: any,
      ): void {if (internalInstance.queue !== null && internalInstance.queue.length > 0) {// 處理更新隊列const oldQueue = internalInstance.queue;// oldReplace:表示是否用新狀態完全替換舊狀態(而非合并)。const oldReplace = internalInstance.replace;// 重置隊列為 null,避免重復處理internalInstance.queue = null;// 重置替換標志internalInstance.replace = false;// 僅一個更新項,直接替換狀態。if (oldReplace && oldQueue.length === 1) {inst.state = oldQueue[0];} else {// 初始化 nextStatelet nextState = oldReplace ? oldQueue[0] : inst.state;// 是否需要創建新對象(避免直接修改舊狀態)let dontMutate = true;// 遍歷更新隊列(從第一個有效更新開始)for (let i = oldReplace ? 1 : 0; i < oldQueue.length; i++) {// 獲取當前更新項const partial = oldQueue[i];const partialState =typeof partial === 'function'// 處理函數式更新(如 setState((state) => ({ ...state, count: state.count + 1 })))? partial.call(inst, nextState, props, maskedLegacyContext)// 非函數式更新直接使用值: partial;if (partialState != null) {if (dontMutate) {// 首次修改,創建新對象以保持不可變性dontMutate = false;nextState = assign({}, nextState, partialState);} else {// 后續修改直接合并(已創建新對象,可安全修改)assign(nextState, partialState);}}}// 最終狀態賦值inst.state = nextState;}} else {// 清空空隊列internalInstance.queue = null;}
      }

      ?<Tag>HostHoistable

      React 渲染流程中處理 可提升資源節點(HostHoistable)。當瀏覽器支持資源優化(supportsResourcestrue)時,會調用 updateHostHoistable 函數對這類節點進行特殊處理,以優化關鍵資源(如 CSS、JavaScript)的加載順序和優先級,從而提升應用性能。

      case HostHoistable:if (supportsResources) {return updateHostHoistable(current, workInProgress, renderLanes);}

      updateHostHoistable

      updateHostHoistable 是 React 渲染流程中處理 可提升資源節點(如 CSS、JS 等) 的核心函數。

      優化關鍵資源的加載執行流程:

      1. 標記 ref 相關副作用
      2. 初始化或更新資源對象(通過 getResource
      3. 管理資源狀態(存儲在 memoizedState 中)
      4. 決定是否創建 DOM 實例(非資源節點或非水合模式下)
      function updateHostHoistable(current: null | Fiber,workInProgress: Fiber,renderLanes: Lanes,
      ) {// 標記出來ref相關副作用markRef(current, workInProgress);// 首次渲染if (current === null) {// 通過 getResource 獲取資源對象(如 CSS、JS 資源)const resource = getResource(workInProgress.type,null,workInProgress.pendingProps,null,);if (resource) {// 將資源對象存儲在 memoizedState 中workInProgress.memoizedState = resource;} else {if (!getIsHydrating()) {// This is not a Resource Hoistable and we aren't hydrating so we construct the instance.// 創建非資源類型的可提升節點(如普通 DOM 元素)workInProgress.stateNode = createHoistableInstance(workInProgress.type,workInProgress.pendingProps,getRootHostContainer(),workInProgress,);}}} else {// Get Resource may or may not return a resource. either way we stash the result// on memoized state.// 對比新舊 props,決定是否需要更新資源// 復用或創建新資源對象,更新到 memoizedStateworkInProgress.memoizedState = getResource(workInProgress.type,current.memoizedProps,workInProgress.pendingProps,current.memoizedState,);}return null;
      }

      工具函數之 markRef

      markRef 函數主要作用是標記 workInProgress Fiber 是否需要執行 ref 相關的副作用(Effect)。

      function markRef(current: Fiber | null, workInProgress: Fiber) {const ref = workInProgress.ref;if (ref === null) {if (current !== null && current.ref !== null) {// Schedule a Ref effectworkInProgress.flags |= Ref | RefStatic;}} else {if (typeof ref !== 'function' && typeof ref !== 'object') {throw new Error('Expected ref to be a function, an object returned by React.createRef(), or undefined/null.',);}if (current === null || current.ref !== ref) {// Schedule a Ref effectworkInProgress.flags |= Ref | RefStatic;}}
      }

      createHoistableInstance

      創建可提升實例?

      function createHoistableInstance(type: string,props: Props,rootContainerInstance: Container,internalInstanceHandle: Object,
      ): Instance {//n獲取document對象const ownerDocument = getOwnerDocumentFromRootContainer(rootContainerInstance,);// 創建elementconst domElement: Instance = ownerDocument.createElement(type);// 用于建立 DOM 節點與 Fiber 節點雙向映射precacheFiberNode(internalInstanceHandle, domElement);// 將 JSX 中的 props 信息存儲到對應 DOM 節點上updateFiberProps(domElement, props);setInitialProperties(domElement, type, props);// 標記 DOM 節點為 可提升(Hoistable) markNodeAsHoistable(domElement);return domElement;
      }

      工具函數之 precacheFiberNode

      precacheFiberNode 是 React 內部用于建立 DOM 節點與 Fiber 節點雙向映射的核心函數。

      function precacheFiberNode(hostInst: Fiber,node: Instance | TextInstance | SuspenseInstance | ReactScopeInstance,
      ): void {(node: any)[internalInstanceKey] = hostInst;
      }const internalInstanceKey = '__reactFiber$' + randomKey;

      工具函數之 updateFiberProps

      updateFiberProps 是 React 內部用于將 JSX 中的 props 信息存儲到對應 DOM 節點上的工具函數。

      function updateFiberProps(node: Instance | TextInstance | SuspenseInstance,props: Props,
      ): void {(node: any)[internalPropsKey] = props;
      }const internalPropsKey = '__reactProps$' + randomKey;

      工具函數之 markNodeAsHoistable

      markNodeAsHoistable 是 React 內部用于標記 DOM 節點為 可提升(Hoistable) 的工具函數。

      function markNodeAsHoistable(node: Node) {(node: any)[internalHoistableMarker] = true;
      }const internalHoistableMarker = '__reactMarker$' + randomKey;

      getResource

      getResource 是 React 內部用于管理和復用關鍵資源(如 CSS、JavaScript 文件)的核心函數。它通過資源根節點(resourceRoot)追蹤已加載的資源,實現資源共享、預加載和避免重復加載,從而優化應用性能。

       function getResource(type: string,currentProps: any,pendingProps: any,currentResource: null | Resource,
      ): null | Resource {// 獲取資源根節點const resourceRoot = getCurrentResourceRoot();if (!resourceRoot) {throw new Error('"resourceRoot" was expected to exist. This is a bug in React.',);}switch (type) {case 'meta':case 'title': {return null;}// 處理資源類型stylecase 'style': {if (// precedence:樣式優先級(如 'high'、'low'),用于控制加載順序。typeof pendingProps.precedence === 'string' &&// href:外部樣式表的 URL。typeof pendingProps.href === 'string') {// 資源鍵生成。getStyleKey:生成 URL 的唯一哈希值,確保相同 URL 的資源被復用。const key = getStyleKey(pendingProps.href);// 查找資源。hoistableStyles:Map 對象,鍵為資源 URL 哈希值,值為資源對象。const styles = getResourcesFromRoot(resourceRoot).hoistableStyles;let resource = styles.get(key);if (!resource) {// 資源對象結構resource = {type: 'style', // 資源類型instance: null, // DOM 實例(加載后填充)count: 0, // 引用計數(用于垃圾回收)state: null, // 資源狀態(如加載中、已完成)};// 將新資源存入緩存styles.set(key, resource);}return resource;}// 無效資源處理return {type: 'void', // 特殊類型,表示無效資源instance: null,count: 0,state: null,};}// 處理資源類型linkcase 'link': {if (// rel="stylesheet":確認是樣式表資源pendingProps.rel === 'stylesheet' &&// href 和 precedence 存在且類型正確typeof pendingProps.href === 'string' &&typeof pendingProps.precedence === 'string') {const qualifiedProps: StylesheetQualifyingProps = pendingProps;// 生成唯一keyconst key = getStyleKey(qualifiedProps.href);// 查找資源const styles = getResourcesFromRoot(resourceRoot).hoistableStyles;let resource = styles.get(key);if (!resource) {const ownerDocument = getDocumentFromRoot(resourceRoot);// 定義資源結構resource = ({type: 'stylesheet',instance: null, // 對應 DOM 元素count: 0, // 引用計數state: {loading: NotLoaded, // 加載狀態preload: null, // 預加載 Promise},}: StylesheetResource);// 存入緩存styles.set(key, resource);// 通過 CSS 選擇器查找已存在的 <link> 標簽const instance = ownerDocument.querySelector(getStylesheetSelectorFromKey(key),);if (instance) {// 使用內部屬性 _p 判斷加載狀態const loadingState: ?Promise<mixed> = (instance: any)._p;if (loadingState) {// This instance is inserted as part of a boundary reveal and is not yet// loaded// 正在加載中} else {// 實例已經加載完成// This instance is already loadedresource.instance = instance;resource.state.loading = Loaded | Inserted;}}// 預加載機制流程:// 生成預加載配置(如 as="style")// 創建 <link rel="preload"> 標簽// 監聽加載完成事件,更新資源狀態if (!preloadPropsMap.has(key)) {const preloadProps = preloadPropsFromStylesheet(qualifiedProps);preloadPropsMap.set(key, preloadProps);if (!instance) {preloadStylesheet(ownerDocument,key,preloadProps,resource.state,);}}}// if (currentProps && currentResource === null) {//   let diff = '';// }return resource;} else {// if (currentProps && currentResource !== null) {//   let diff = '';// }return null;}}case 'script': {const async = pendingProps.async;const src = pendingProps.src;if (typeof src === 'string' &&async &&typeof async !== 'function' &&typeof async !== 'symbol') {const key = getScriptKey(src);const scripts = getResourcesFromRoot(resourceRoot).hoistableScripts;let resource = scripts.get(key);if (!resource) {resource = {type: 'script',instance: null,count: 0,state: null,};scripts.set(key, resource);}return resource;}return  {type: 'void',instance: null,count: 0,state: null,};}default: {throw new Error(`getResource encountered a type it did not expect: "${type}". this is a bug in React.`,);}}
      }

      1、處理style類型的資源

      處理 外部樣式表資源(<style> 標簽) 的邏輯分支。它通過 precedencehref 屬性識別需要優化加載的樣式資源,利用緩存機制避免重復加載,并返回標準化的資源對象。

      2、處理link類型的資源

      React 內部處理 <link rel="stylesheet"> 資源的核心邏輯,主要負責:

      1. 資源去重:通過 URL 緩存避免重復加載同一 CSS 文件
      2. 狀態管理:跟蹤樣式表的加載狀態(未加載、加載中、已完成)
      3. 預加載優化:使用 <link rel="preload"> 加速關鍵樣式的加載
      4. 服務端渲染集成:支持與 SSR 流程配合,提前收集關鍵 CSS

      3、處理script類型的資源

      ?

      工具函數之 preloadPropsFromStylesheet

      preloadPropsFromStylesheet 是 React 內部用于將 <link rel="stylesheet"> 轉換為 <link rel="preload"> 的工具函數。

      function preloadPropsFromStylesheet(props: StylesheetQualifyingProps,
      ): PreloadProps {return {rel: 'preload', // 將 rel 從 'stylesheet' 改為 'preload'as: 'style', // 指定資源類型為樣式表href: props.href, // 保留原始 URLcrossOrigin: props.crossOrigin, // 跨域配置integrity: props.integrity,  // 內容完整性校驗media: props.media, // 媒體查詢條件hrefLang: props.hrefLang,  // 語言設置referrerPolicy: props.referrerPolicy, // 引用策略};
      }

      // 原始 JSX
      <link rel="stylesheet" href="critical.css" precedence="high" />// React 處理后
      <link rel="preload" as="style" href="critical.css" />  // 預加載階段
      <link rel="stylesheet" href="critical.css" />         // 正式應用階段

      工具函數之 preloadStylesheet

      preloadStylesheet 是 React 內部用于預加載 CSS 資源的核心函數,通過創建 <link rel="preload"> 標簽實現樣式表的并行加載,避免阻塞主線程渲染。

      function preloadStylesheet(ownerDocument: Document,key: string,preloadProps: PreloadProps,state: StylesheetState,
      ) {// 檢查已有預加載標簽const preloadEl = ownerDocument.querySelector(getPreloadStylesheetSelectorFromKey(key),);if (preloadEl) {// If we find a preload already it was SSR'd and we won't have an actual// loading state to track. For now we will just assume it is loaded// 服務端渲染已插入預加載標簽,直接標記為已加載state.loading = Loaded;} else {// 創建預加載標簽const instance = ownerDocument.createElement('link');state.preload = instance;// 監聽加載事件instance.addEventListener('load', () => (state.loading |= Loaded));instance.addEventListener('error', () => (state.loading |= Errored));// 設置標簽屬性并插入文檔setInitialProperties(instance, 'link', preloadProps);markNodeAsHoistable(instance); // 標記為可提升資源(ownerDocument.head: any).appendChild(instance); // 插入到文檔頭部}
      }
      function getPreloadStylesheetSelectorFromKey(key: string) {return `link[rel="preload"][as="style"][${key}]`;
      }

      工具函數之 getCurrentResourceRoot

      getCurrentResourceRoot() 是 React 內部用于獲取當前渲染環境中 可提升資源根節點(HoistableRoot) 的工具函數。

      function getCurrentResourceRoot(): null | HoistableRoot {// 獲取當前根容器const currentContainer = getCurrentRootHostContainer();// getHoistableRoot提取可提升資源根節點return currentContainer ? getHoistableRoot(currentContainer) : null;
      }
      function getCurrentRootHostContainer(): null | Container {return rootInstanceStackCursor.current;
      }
      function createCursor<T>(defaultValue: T): StackCursor<T> {return {current: defaultValue,};
      }

      ?工具函數之 getHoistableRoot

      function getHoistableRoot(container: Container): HoistableRoot {return typeof container.getRootNode === 'function'// Node 接口的 getRootNode() 方法返回上下文中的根節點?  container.getRootNode()// Node.ownerDocument 只讀屬性會返回當前節點的頂層的 document 對象: container.ownerDocument;
      }

      工具函數之 getResourcesFromRoot?

      function getResourcesFromRoot(root: HoistableRoot): RootResources {// 獲取節點上的設置的資源let resources = (root: any)[internalRootNodeResourcesKey];if (!resources) {// 設置resources = (root: any)[internalRootNodeResourcesKey] = {hoistableStyles: new Map(),hoistableScripts: new Map(),};}return resources;
      }const internalRootNodeResourcesKey = '__reactResources$' + randomKey;

      ?<Tag>HostSingleton

      React 渲染流程中處理 單節點宿主組件。

      
      // Fall through
      case HostSingleton:if (supportsSingletons) {return updateHostSingleton(current, workInProgress, renderLanes);}

      updateHostSingleton

      updateHostSingleton 是 React 渲染流程中處理 單節點宿主組件(如 <div><span> 等 DOM 元素) 的核心函數。

      function updateHostSingleton(current: Fiber | null,workInProgress: Fiber,renderLanes: Lanes,
      ) {// 將當前 Fiber 節點的上下文(如命名空間、文檔模式)壓入棧中pushHostContext(workInProgress);if (current === null) {// 服務端渲染水合處理// claimHydratableSingleton(workInProgress);}const nextChildren = workInProgress.pendingProps.children;// 首次渲染if (current === null && !getIsHydrating()) {// 使用 reconcileChildFibers 創建新的子 Fiber 樹workInProgress.child = reconcileChildFibers(workInProgress,null,nextChildren,renderLanes,);} else {// 更新// 使用 reconcileChildren 對比新舊子節點,執行最小化 DOM 操作reconcileChildren(current, workInProgress, nextChildren, renderLanes);}// 標記ref副作用markRef(current, workInProgress);// 返回子 Fiber 節點return workInProgress.child;
      }
      

      ?<Tag>HostComponent?

      React 渲染流程中處理 宿主組件(如 HTML 標簽)。

      // Fall through
      case HostComponent:return updateHostComponent(current, workInProgress, renderLanes);

      工具函數之 updateHostComponent

      updateHostComponent 是 React 渲染流程中處理 宿主組件(如 HTML 標簽) 的核心函數。

      function updateHostComponent(current: Fiber | null,workInProgress: Fiber,renderLanes: Lanes,
      ) {if (current === null) {// tryToClaimNextHydratableInstance(workInProgress);}// 設置當前渲染上下文pushHostContext(workInProgress);const type = workInProgress.type;const nextProps = workInProgress.pendingProps;const prevProps = current !== null ? current.memoizedProps : null;let nextChildren = nextProps.children;const isDirectTextChild = shouldSetTextContent(type, nextProps);// 對于純文本子節點(如 <div>Hello</div>),直接設置 textContent// 避免創建額外的文本節點,提升渲染效率if (isDirectTextChild) {nextChildren = null;} else if (prevProps !== null && shouldSetTextContent(type, prevProps)) {// If we're switching from a direct text child to a normal child, or to// empty, we need to schedule the text content to be reset.workInProgress.flags |= ContentReset;}// 異步狀態處理(并發模式)if (enableAsyncActions) {const memoizedState = workInProgress.memoizedState;if (memoizedState !== null) {// renderTransitionAwareHostComponentWithHooks 處理異步更新const newState = renderTransitionAwareHostComponentWithHooks(current,workInProgress,renderLanes,);// 根據渲染器類型(主渲染器或輔助渲染器)更新上下文值if (isPrimaryRenderer) {// _currentValue 存儲主渲染器的上下文值HostTransitionContext._currentValue = newState;} else {// _currentValue2 存儲輔助渲染器的上下文值HostTransitionContext._currentValue2 = newState;}// 懶傳播if (enableLazyContextPropagation) {// In the lazy propagation implementation, we don't scan for matching// consumers until something bails out.} else {if (didReceiveUpdate) {if (current !== null) {const oldStateHook: Hook = current.memoizedState;const oldState: TransitionStatus = oldStateHook.memoizedState;if (oldState !== newState) {// 更新上下文并傳播變化propagateContextChange(workInProgress,HostTransitionContext,renderLanes,);}}}}}}markRef(current, workInProgress);// 協調子節點reconcileChildren(current, workInProgress, nextChildren, renderLanes);return workInProgress.child;
      }

      renderTransitionAwareHostComponentWithHooks?

      處理hook鉤子函數。

      function renderTransitionAwareHostComponentWithHooks(current: Fiber | null,workInProgress: Fiber,lanes: Lanes,
      ): TransitionStatus {if (!enableAsyncActions) {throw new Error('Not implemented.');}return renderWithHooks(current,workInProgress,TransitionAwareHostComponent,null,null,lanes,);
      }

      工具函數之 propagateContextChange?

      function propagateContextChange<T>(workInProgress: Fiber,context: ReactContext<T>,renderLanes: Lanes,
      ): void {if (enableLazyContextPropagation) {const forcePropagateEntireTree = true;propagateContextChanges(workInProgress,[context],renderLanes,forcePropagateEntireTree,);} else {propagateContextChange_eager(workInProgress, context, renderLanes);}
      }

      工具函數之 propagateContextChange_eager

      propagateContextChange_eager 是 React 中用于 主動傳播上下文變化 的核心函數(適用于非懶傳播模式)。當上下文(Context)的值發生改變時,該函數會遍歷相關 Fiber 樹,找到依賴該上下文的組件并為其標記更新,確保組件能響應上下文變化并重新渲染。

      function propagateContextChange_eager<T>(workInProgress: Fiber,context: ReactContext<T>,renderLanes: Lanes,
      ): void {// Only used by eager implementationif (enableLazyContextPropagation) {return;}// Fiber 樹遍歷初始化let fiber = workInProgress.child;if (fiber !== null) {// Set the return pointer of the child to the work-in-progress fiber.// 設置子節點的 return 指針指向父節點fiber.return = workInProgress;}// 深度優先遍歷循環while (fiber !== null) {let nextFiber;// Visit this fiber.// 獲取當前節點依賴的上下文列表const list = fiber.dependencies;if (list !== null) {nextFiber = fiber.child;let dependency = list.firstContext;while (dependency !== null) {// Check if the context matches.// 匹配到目標上下文,觸發更新邏輯if (dependency.context === context) {// Match! Schedule an update on this fiber.// 為類組件生成強制更新if (fiber.tag === ClassComponent) {// Schedule a force update on the work-in-progress.const lane = pickArbitraryLane(renderLanes);const update = createUpdate(lane);update.tag = ForceUpdate;// Inlined `enqueueUpdate` to remove interleaved update check// 入隊更新(直接操作隊列,避免中間檢查)const updateQueue = fiber.updateQueue;if (updateQueue === null) {// Only occurs if the fiber has been unmounted.} else {const sharedQueue: SharedQueue<any> = (updateQueue: any).shared;const pending = sharedQueue.pending;// update是是一個循環鏈表結構if (pending === null) {// This is the first update. Create a circular list.update.next = update;} else {update.next = pending.next;pending.next = update;}sharedQueue.pending = update;}}// 標記當前節點及其 alternate 節點的更新優先級fiber.lanes = mergeLanes(fiber.lanes, renderLanes);const alternate = fiber.alternate;if (alternate !== null) {// 合并車道alternate.lanes = mergeLanes(alternate.lanes, renderLanes);}// 向上傳播任務到父路徑scheduleContextWorkOnParentPath(fiber.return,renderLanes,workInProgress,);// Mark the updated lanes on the list, too.list.lanes = mergeLanes(list.lanes, renderLanes);// Since we already found a match, we can stop traversing the// dependency list.// 找到一個匹配后,無需繼續遍歷依賴列表break;}dependency = dependency.next;}} else if (fiber.tag === ContextProvider) {// Don't scan deeper if this is a matching provider// 若當前節點是匹配的 Provider,停止向下遍歷(避免重復處理)nextFiber = fiber.type === workInProgress.type ? null : fiber.child;} else if (fiber.tag === DehydratedFragment) {// 處理 Suspense 邊界的脫水片段,標記其父 Suspense 節點const parentSuspense = fiber.return;if (parentSuspense === null) {throw new Error('We just came from a parent so we must have had a parent. This is a bug in React.',);}parentSuspense.lanes = mergeLanes(parentSuspense.lanes, renderLanes);const alternate = parentSuspense.alternate;if (alternate !== null) {alternate.lanes = mergeLanes(alternate.lanes, renderLanes);}scheduleContextWorkOnParentPath(parentSuspense,renderLanes,workInProgress,);// 跳過子樹,直接處理兄弟節點nextFiber = fiber.sibling;} else {// Traverse down.nextFiber = fiber.child;}if (nextFiber !== null) {// Set the return pointer of the child to the work-in-progress fiber.nextFiber.return = fiber;} else {// No child. Traverse to next sibling.nextFiber = fiber;while (nextFiber !== null) {if (nextFiber === workInProgress) {// We're back to the root of this subtree. Exit.nextFiber = null;break;}const sibling = nextFiber.sibling;if (sibling !== null) {// Set the return pointer of the sibling to the work-in-progress fiber.sibling.return = nextFiber.return;nextFiber = sibling;break;}// No more siblings. Traverse up.nextFiber = nextFiber.return;}}fiber = nextFiber;}
      }

      工具函數之 scheduleContextWorkOnParentPath

      scheduleContextWorkOnParentPath 是 React 中用于 向上傳播上下文更新任務 的核心函數

      function scheduleContextWorkOnParentPath(parent: Fiber | null,renderLanes: Lanes,propagationRoot: Fiber,
      ) {// Update the child lanes of all the ancestors, including the alternates.let node = parent;// 從當前父節點出發遍歷while (node !== null) {// 獲取備用 Fiber 節點(雙緩沖機制)const alternate = node.alternate;// 檢查當前節點的 childLanes 是否包含新的 renderLanesif (!isSubsetOfLanes(node.childLanes, renderLanes)) {// 合并車道node.childLanes = mergeLanes(node.childLanes, renderLanes);if (alternate !== null) {// 同步更新備用節點alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes);}} else if (alternate !== null &&!isSubsetOfLanes(alternate.childLanes, renderLanes)) {alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes);}//  到達傳播根節點,停止遍歷if (node === propagationRoot) {break;}// 向上處理父節點node = node.return;}
      }
      

      ?<Tag>HostText?

      case HostText:return updateHostText(current, workInProgress);

      updateHostText?

      function updateHostText(current: null | Fiber, workInProgress: Fiber) {// 說明首次渲染或沒有可對比的舊fiberif (current === null) {//tryToClaimNextHydratableTextInstance(workInProgress);}return null;
      }

      ?<Tag>HostPortal?

      case HostPortal:return updatePortalComponent(current, workInProgress, renderLanes);

      updatePortalComponent?

      function updatePortalComponent(current: Fiber | null,workInProgress: Fiber,renderLanes: Lanes,
      ) {pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo);const nextChildren = workInProgress.pendingProps;if (current === null) {workInProgress.child = reconcileChildFibers(workInProgress,null,nextChildren,renderLanes,);} else {reconcileChildren(current, workInProgress, nextChildren, renderLanes);}return workInProgress.child;
      }

      渲染階段二completeUnitOfWork

      completeUnitOfWork 函數在 React 的協調過程中負責完成單個 Fiber 節點的工作單元。它會不斷嘗試完成當前 Fiber 節點的工作,處理可能出現的未完成情況,根據處理結果決定是繼續處理兄弟節點還是返回父節點,直到完成整個 Fiber 樹的工作,并在到達根節點時更新根節點的退出狀態。

      執行過程:

      1. 初始化當前要處理的 filbert 節點,定義為completedWork。
      2. do...while 循環,直到completedWork 為 null。
        1. 如果 fiber 是否存在未完成的工作,調用 unwindUnitOfWork 函數處理未完成的工作,然后跳出 do...while 循環。
        2. 沒有未完成的工作,則調用 completeWork 完成當前節點的工作。
      function completeUnitOfWork(unitOfWork: Fiber): void {// completedWork 初始化為傳入的 unitOfWorklet completedWork: Fiber = unitOfWork;// 使用 do-while 循環來處理 Fiber 節點的工作do {// 檢查 completedWork 的 flags 屬性中是否包含 Incomplete 標志。如果包含,說明當前 Fiber 節點的工作未完成。if ((completedWork.flags & Incomplete) !== NoFlags) {const skipSiblings = workInProgressRootDidSkipSuspendedSiblings;// 用 unwindUnitOfWork 函數處理未完成的工作unwindUnitOfWork(completedWork, skipSiblings);return;}// 獲取當前 Fiber 節點的替代節點,用于存儲舊的狀態。const current = completedWork.alternate;// 獲取當前 Fiber 節點的父節點,用于在完成當前節點工作后返回父節點繼續處理。const returnFiber = completedWork.return;// 用于存儲 completeWork 函數返回的下一個要處理的 Fiber 節點。let next;// 調用 startProfilerTimer 函數開始記錄性能分析時間。// startProfilerTimer(completedWork);// 調用 completeWork 函數完成當前 Fiber 節點的工作,傳入當前 Fiber 節點的替代節點 current、當前 Fiber 節點 completedWork 以及相關的渲染車道 entangledRenderLanes。next = completeWork(current, completedWork, entangledRenderLanes);// 如果 next 不為 null,說明完成當前 Fiber 節點的工作產生了新的工作。if (next !== null) {// Completing this fiber spawned new work. Work on that next.// 將 next 賦值給 workInProgress,表示下一個要處理的 Fiber 節點成為當前的工作進行中的節點,函數直接返回。workInProgress = next;return;}// 獲取當前 Fiber 節點的兄弟節點 siblingFiber。const siblingFiber = completedWork.sibling;if (siblingFiber !== null) {// If there is more work to do in this returnFiber, do that next.// 如果兄弟節點不為 null,將兄弟節點賦值給 workInProgress,表示接下來要處理兄弟節點的工作,函數直接返回。workInProgress = siblingFiber;return;}// 如果沒有新產生的工作,也沒有兄弟節點,將 completedWork 更新為其父節點 returnFiber,同時更新 workInProgress 為父節點,繼續處理父節點的工作。completedWork = returnFiber;// Update the next thing we're working on in case something throws.workInProgress = completedWork;// 只要 completedWork 不為 null,就會繼續循環處理。} while (completedWork !== null);// We've reached the root.// 如果根節點的退出狀態為 RootInProgress(正在進行中),將其更新為 RootCompleted(已完成)。if (workInProgressRootExitStatus === RootInProgress) {workInProgressRootExitStatus = RootCompleted;}
      }
      

      completeWork

      completeWork 函數的主要職責是根據當前 Fiber 節點的類型(通過 workInProgress.tag 標識),對該節點進行相應的處理,比如更新 DOM、設置屬性等。(負責單個fiber節點的處理)

      function completeWork(current: Fiber | null,workInProgress: Fiber,renderLanes: Lanes,
      ): Fiber | null {const newProps = workInProgress.pendingProps;popTreeContext(workInProgress);switch (workInProgress.tag) {// 省略的代碼case Throw: {if (!disableLegacyMode) {// Only Legacy Mode completes an errored node.return null;}}}throw new Error(`Unknown unit of work tag (${workInProgress.tag}). This error is likely caused by a bug in ` +'React. Please file an issue.',);
      }

      ?<Tag>FunctionComponent/LazyComponent/ForwardRef/...

      case LazyComponent:
      case SimpleMemoComponent:
      case FunctionComponent:
      case ForwardRef:
      case Fragment:
      case Mode:
      case Profiler:
      case ContextConsumer:
      case MemoComponent:bubbleProperties(workInProgress);return null;
      

      bubbleProperties

      bubbleProperties 函數的主要功能是從一個已完成工作的 Fiber 節點(completedWork)的子節點中收集信息,將這些信息冒泡到該節點上。這些信息主要包括子節點的渲染優先級車道(Lanes)和副作用標志(Flags)。

      function bubbleProperties(completedWork: Fiber) {// 如果 completedWork 存在替代節點(alternate),并且替代節點的子節點與當前節點的子節點相同,則認為可以跳過更新。const didBailout =completedWork.alternate !== null &&completedWork.alternate.child === completedWork.child;// 用于存儲合并后的子節點的渲染優先級車道,初始化為 NoLanes(表示沒有車道)。let newChildLanes: Lanes = NoLanes;// 用于存儲合并后的子節點的副作用標志,初始化為 NoFlags(表示沒有標志)。let subtreeFlags = NoFlags;// 未跳過更新的情況if (!didBailout) {let child = completedWork.child;// 使用 while 循環遍歷 completedWork 的所有子節點:while (child !== null) {// 合并子節點的 lanes 和 childLanes 到newChildLanesnewChildLanes = mergeLanes(newChildLanes,mergeLanes(child.lanes, child.childLanes),);// 將子節點的 subtreeFlags 和 flags 合并到 subtreeFlags 中subtreeFlags |= child.subtreeFlags;subtreeFlags |= child.flags;child.return = completedWork;// 繼續下一個兄弟節點child = child.sibling;}// 更新completedWork.subtreeFlags |= subtreeFlags;} else {let child = completedWork.child;while (child !== null) {// 合并子節點的 lanes 和 childLanes 到 newChildLanes 中。newChildLanes = mergeLanes(newChildLanes,mergeLanes(child.lanes, child.childLanes),);// ignore them.// 使用按位與運算符 & 過濾掉非靜態的標志(通過 StaticMask)。subtreeFlags |= child.subtreeFlags & StaticMask;subtreeFlags |= child.flags & StaticMask;child.return = completedWork;child = child.sibling;}completedWork.subtreeFlags |= subtreeFlags;}completedWork.childLanes = newChildLanes;return didBailout;
      }

      ?<Tag>HostRoot

      React 處理 HostRoot 類型節點(即應用根節點)的核心邏輯,主要負責完成根節點渲染后的環境清理、狀態同步和副作用標記。

      case HostRoot: {// 1、獲取 FiberRoot 實例,React 應用的根對象,包含應用狀態、優先級隊列等核心信息。const fiberRoot = (workInProgress.stateNode: FiberRoot);//2、緩存處理if (enableCache) {let previousCache: Cache | null = null;if (current !== null) {previousCache = current.memoizedState.cache;}const cache: Cache = workInProgress.memoizedState.cache;// 比較新舊緩存對象,若不同則標記 Passive 副作用(如 useEffect)if (cache !== previousCache) {// Run passive effects to retain/release the cache.workInProgress.flags |= Passive;}// 清理緩存上下文棧popCacheProvider(workInProgress, cache);}// 3、環境狀態恢復// 彈出過渡狀態:結束當前渲染的過渡(如 startTransition)。popRootTransition(workInProgress, fiberRoot, renderLanes);// 彈出宿主容器:恢復 DOM 根節點上下文(見 popHostContainer 函數)popHostContainer(workInProgress);// 彈出遺留上下文:清理舊版 context API 的狀態。popTopLevelLegacyContextObject(workInProgress);// 4、上下文狀態同步// 在渲染過程中收集的新上下文值,在此處應用到根節點。if (fiberRoot.pendingContext) {fiberRoot.context = fiberRoot.pendingContext;fiberRoot.pendingContext = null;}//5、處理水合// 處理首次渲染或無子節點的情況if (current === null || current.child === null) {// If we hydrated, pop so that we can delete any remaining children// that weren't hydrated.// popHydrationState:清理水合過程中的臨時狀態,并返回是否成功水合。const wasHydrated = popHydrationState(workInProgress);// 水合成功if (wasHydrated) {// emitPendingHydrationWarnings();// 標記更新,可能用于處理殘留的 DOM 差異。// markUpdate(workInProgress);} else {// 未水合或水合失敗的處理if (current !== null) {const prevState: RootState = current.memoizedState;if (// Check if this is a client root// 非脫水狀態(純客戶端渲染)!prevState.isDehydrated ||// Check if we reverted to client rendering (e.g. due to an error)// 強制客戶端渲染標志(如水合錯誤)(workInProgress.flags & ForceClientRender) !== NoFlags) {// Snapshot 標志:觸發 getSnapshotBeforeUpdate 生命周期(若適用)。workInProgress.flags |= Snapshot;// upgradeHydrationErrorsToRecoverable:將水合錯誤轉換為可恢復錯誤,避免整頁崩潰。upgradeHydrationErrorsToRecoverable();}}}}// 6、更新宿主容器與冒泡屬性// 更新宿主容器:生成 DOM 更新隊列(如屬性變化、子節點增刪)。updateHostContainer(current, workInProgress);// 冒泡屬性:向上傳遞子樹的狀態(如是否有副作用、優先級信息)。bubbleProperties(workInProgress);return null;
      }

      updateHostContainer

      updateHostContainer 是 React 中處理宿主容器(如 DOM 根節點或 Portal 容器)更新的核心函數。當啟用持久化渲染(supportsPersistence)且需要克隆容器時,該函數會創建新的子節點集合,標記更新,并最終觸發容器的子節點替換。

      function updateHostContainer(current: null | Fiber, workInProgress: Fiber) {// supportsPersistence:是否啟用持久化渲染(如 React 18+ 的并發模式)。if (supportsPersistence) {// oesRequireClone:判斷是否需要克隆容器(如子節點結構變化、屬性更新等)。if (doesRequireClone(current, workInProgress)) {// 創建新子節點集合const portalOrRoot: {containerInfo: Container,pendingChildren: ChildSet,} = workInProgress.stateNode;const container = portalOrRoot.containerInfo;// 創建用于存儲子節點的臨時集合。const newChildSet = createContainerChildSet();// If children might have changed, we have to add them all to the set.// appendAllChildrenToContainer將 workInProgress 的所有子節點添加到新集合。appendAllChildrenToContainer(newChildSet,workInProgress,/* needsVisibilityToggle */ false,/* isHidden */ false,);portalOrRoot.pendingChildren = newChildSet;// Schedule an update on the container to swap out the container.// 標記容器需要更新,觸發后續的 DOM 操作。markUpdate(workInProgress);// 準備容器的子節點更新,可能包括:// 計算新舊子節點的差異。// 準備插入 / 刪除 / 移動等 DOM 操作隊列。finalizeContainerChildren(container, newChildSet);}}
      }

      工具函數之 doesRequireClone

      doesRequireClone?函數用于判斷是否需要克隆宿主容器(如 DOM 節點)以應用更新。

      function doesRequireClone(current: null | Fiber, completedWork: Fiber) {const didBailout = current !== null && current.child === completedWork.child;// 若組件因 bailout 機制跳過渲染(如 React.memo 優化),直接返回 false(無需克隆)。if (didBailout) {return false;}// ChildDeletion 標志:表示子樹中存在節點刪除操作,需克隆容器以安全移除節點。if ((completedWork.flags & ChildDeletion) !== NoFlags) {return true;}// TODO: If we move the `doesRequireClone` call after `bubbleProperties`// then we only have to check the `completedWork.subtreeFlags`.let child = completedWork.child;while (child !== null) {// Cloned:節點需要被克隆。// Visibility:節點可見性變化(如通過 Suspense 控制)。// Placement:節點插入或移動。// ChildDeletion:子節點刪除。// 持久化模式(enablePersistedModeClonedFlag 啟用const checkedFlags = enablePersistedModeClonedFlag? Cloned | Visibility | Placement | ChildDeletion// 傳統模式:檢查 MutationMask(包含 Placement、Update、Deletion 等基本變更)。: MutationMask;// child.flags:當前節點的變更標志。// child.subtreeFlags:子樹中所有節點的累積變更標志。if ((child.flags & checkedFlags) !== NoFlags ||(child.subtreeFlags & checkedFlags) !== NoFlags) {return true;}child = child.sibling;}return false;
      }

      工具函數之 createContainerChildSet

      createContainerChildSet 是 React 中用于創建子節點集合的工廠函數,主要服務于宿主容器(如 DOM 根節點或 Portal)的更新過程。

      createContainerChildSet(): Array<Instance | TextInstance> {return [];
      },

      工具函數之 appendAllChildrenToContainer

      appendAllChildrenToContainer 是 React 渲染流程中的核心函數,用于將 Fiber 樹中的子節點遞歸轉換為實際渲染節點(如 DOM 元素)并添加到容器中。

      function appendAllChildrenToContainer(containerChildSet: ChildSet, // 目標容器子節點集合workInProgress: Fiber, // 當前處理的 Fiber 節點needsVisibilityToggle: boolean, // 是否需要控制可見性isHidden: boolean,  // 當前是否隱藏
      ) {if (supportsPersistence) {// We only have the top Fiber that was created but we need recurse down its// children to find all the terminal nodes.let node = workInProgress.child;while (node !== null) {// 節點類型處理// 1、HostComponent:DOM 元素(如 <div>)。if (node.tag === HostComponent) {let instance = node.stateNode;if (needsVisibilityToggle && isHidden) {// This child is inside a timed out tree. Hide it.const props = node.memoizedProps;const type = node.type;instance = cloneHiddenInstance(instance, type, props);}// 將實例添加到子節點集合中appendChildToContainerChildSet(containerChildSet, instance);// 2、處理文本} else if (node.tag === HostText) {let instance = node.stateNode;if (needsVisibilityToggle && isHidden) {// This child is inside a timed out tree. Hide it.const text = node.memoizedProps;instance = cloneHiddenTextInstance(instance, text);}appendChildToContainerChildSet(containerChildSet, instance);// 3、處理HostPortal} else if (node.tag === HostPortal) {// Portal 節點不遞歸處理子節點(由 Portal 單獨管理)// 4、處理不可見組件} else if (node.tag === OffscreenComponent &&node.memoizedState !== null) {const child = node.child;if (child !== null) {child.return = node;}// If Offscreen is not in manual mode, detached tree is hidden from user space.const _needsVisibilityToggle = !isOffscreenManual(node);appendAllChildrenToContainer(containerChildSet,node,/* needsVisibilityToggle */ _needsVisibilityToggle,/* isHidden */ true,);// 遞歸到子節點} else if (node.child !== null) {node.child.return = node;node = node.child;continue;}node = (node: Fiber);if (node === workInProgress) {return;}// 回溯到父節點while (node.sibling === null) {if (node.return === null || node.return === workInProgress) {return;}node = node.return;}node.sibling.return = node.return;node = node.sibling;}}
      }

      ?工具函數之 appendChildToContainerChildSet

      appendChildToContainerChildSet 是 React 內部用于將子節點添加到容器子節點集合的輔助函數。

      appendChildToContainerChildSet(childSet: Array<Instance | TextInstance>,child: Instance | TextInstance,): void {childSet.push(child);
      },

      工具函數之?appendAllChildrenToContainer?

      appendAllChildrenToContainer 是 React 渲染流程中的核心函數,用于將 Fiber 樹中的子節點遞歸轉換為實際渲染節點(如 DOM 元素)并添加到容器中。該函數處理多種節點類型(組件、文本、Portal 等),支持可見性控制,并在持久化渲染模式下優化節點添加邏輯。

      function appendAllChildrenToContainer(containerChildSet: ChildSet, // 目標容器子節點集合workInProgress: Fiber, // 當前處理的 Fiber 節點needsVisibilityToggle: boolean, // 是否需要控制可見性isHidden: boolean,  // 當前是否隱藏
      ) {if (supportsPersistence) {// We only have the top Fiber that was created but we need recurse down its// children to find all the terminal nodes.let node = workInProgress.child;while (node !== null) {// 節點類型處理// 1、HostComponent:DOM 元素(如 <div>)。if (node.tag === HostComponent) {let instance = node.stateNode;if (needsVisibilityToggle && isHidden) {// This child is inside a timed out tree. Hide it.const props = node.memoizedProps;const type = node.type;instance = cloneHiddenInstance(instance, type, props);}appendChildToContainerChildSet(containerChildSet, instance);// 2、處理文本} else if (node.tag === HostText) {let instance = node.stateNode;if (needsVisibilityToggle && isHidden) {// This child is inside a timed out tree. Hide it.const text = node.memoizedProps;instance = cloneHiddenTextInstance(instance, text);}appendChildToContainerChildSet(containerChildSet, instance);// 3、處理HostPortal} else if (node.tag === HostPortal) {// Portal 節點不遞歸處理子節點(由 Portal 單獨管理)// 4、處理不可見組件} else if (node.tag === OffscreenComponent &&node.memoizedState !== null) {const child = node.child;if (child !== null) {child.return = node;}// If Offscreen is not in manual mode, detached tree is hidden from user space.const _needsVisibilityToggle = !isOffscreenManual(node);appendAllChildrenToContainer(containerChildSet,node,/* needsVisibilityToggle */ _needsVisibilityToggle,/* isHidden */ true,);// 遞歸到子節點} else if (node.child !== null) {node.child.return = node;node = node.child;continue;}node = (node: Fiber);if (node === workInProgress) {return;}// 回溯或處理兄弟節點while (node.sibling === null) {if (node.return === null || node.return === workInProgress) {return;}node = node.return;}node.sibling.return = node.return;node = node.sibling;}}
      }

      工具函數之?finalizeContainerChildren?

      ?finalizeContainerChildren?函數用于將新生成的子節點集合(newChildren)關聯到容器(container)。

      finalizeContainerChildren(container: Container,newChildren: Array<Instance | TextInstance>,
      ): void {container.pendingChildren = newChildren;if (newChildren.length === 1 &&newChildren[0].text === 'Error when completing root') {// Trigger an error for testing purposesthrow Error('Error when completing root');}
      },

      <Tag>HostHoistable

      處理 React 中 HostHoistable 類型的 Fiber 節點,主要用于優化和管理可提升的宿主環境組件(如 DOM 元素)。這類組件可能包含異步資源(如圖片、腳本),需要特殊的預加載和掛起邏輯。代碼根據組件是否包含資源(Resource)以及是否處于更新階段,選擇不同的處理路徑,確保資源預加載和組件渲染的高效性與正確性。

      執行過程(啟用資源管理):

      一、初始化過程

      1. 標記更新。
      2. 處理資源類型。
      3. 處理普通實例類型。

      二、更新過程

      1. 資源存在
        1. 資源存在變化。標記更新。
        2. 資源未發生變化。清除掛起標記。
      2. 普通實例
        1. 支持突變模式。當props發生變化化,標記更新。
        2. 不支持突變模式,調用updateHostComponent函數。
      case HostHoistable: {if (supportsResources) {const type = workInProgress.type;const nextResource: Resource | null = workInProgress.memoizedState;// 初始化if (current === null) {// 標記更新markUpdate(workInProgress);if (nextResource !== null) {// 處理資源類型bubbleProperties(workInProgress);preloadResourceAndSuspendIfNeeded(workInProgress,nextResource,type,newProps,renderLanes,);return null;} else {// 處理普通實例bubbleProperties(workInProgress);preloadInstanceAndSuspendIfNeeded(workInProgress,type,newProps,renderLanes,);return null;}} else {// This is an update.if (nextResource) {// This is a Resourceif (nextResource !== current.memoizedState) {//  資源變化,觸發更新和預加載// we have a new Resource. we need to updatemarkUpdate(workInProgress);// This must come at the very end of the complete phase.bubbleProperties(workInProgress);preloadResourceAndSuspendIfNeeded(workInProgress,nextResource,type,newProps,renderLanes,);return null;} else {// This must come at the very end of the complete phase.bubbleProperties(workInProgress);// 資源未變化,清除掛起標志workInProgress.flags &= ~MaySuspendCommit;return null;}} else {// 更新階段且為普通實例// This is an Instance// We may have props to update on the Hoistable instance.if (supportsMutation) {const oldProps = current.memoizedProps;if (oldProps !== newProps) {markUpdate(workInProgress);}} else {// We use the updateHostComponent path becuase it produces// the update queue we need for Hoistables.updateHostComponent(current,workInProgress,type,newProps,renderLanes,);}// This must come at the very end of the complete phase.bubbleProperties(workInProgress);preloadInstanceAndSuspendIfNeeded(workInProgress,type,newProps,renderLanes,);return null;}}}// Fall through
      }

      ?工具函數之 preloadResourceAndSuspendIfNeeded

      preloadResourceAndSuspendIfNeeded 是 React 內部用于處理異步資源預加載的核心函數,主要針對 HostHoistable 類型的 Fiber 節點(如媒體元素、腳本等)。其核心邏輯是:嘗試預加載資源,如果資源未就緒則掛起當前渲染,避免阻塞主線程。該函數實現了 React 的并發渲染特性,確保在資源加載期間頁面保持響應,并根據配置決定是顯示舊內容還是立即掛起。

      function preloadResourceAndSuspendIfNeeded(workInProgress: Fiber,resource: Resource,type: Type,props: Props,renderLanes: Lanes,
      ) {// This is a fork of preloadInstanceAndSuspendIfNeeded, but for resources.// mayResourceSuspendCommit 判斷資源是否可能導致掛起。if (!mayResourceSuspendCommit(resource)) {// 若不可能掛起(如資源已緩存),清除掛起標志并直接返回。workInProgress.flags &= ~MaySuspendCommit;return;}// 標記可能掛起狀態workInProgress.flags |= MaySuspendCommit;const isReady = preloadResource(resource);// 資源未就緒if (!isReady) {if (shouldRemainOnPreviousScreen()) {// 標記 ShouldSuspendCommit 標志,等待資源就緒后再提交更新。workInProgress.flags |= ShouldSuspendCommit;} else {// 資源已就緒// 立即調用 suspendCommit() 掛起當前渲染,觸發 Suspense 邊界的 fallback。suspendCommit();}}
      }

      <Tag>HostSingleton

      處理 React 中 HostSingleton 類型的 Fiber 節點,用于表示必須在整個應用中唯一存在的宿主環境組件。

      case HostSingleton: {// 支持單例if (supportsSingletons) {// 彈出當前 Fiber 的宿主環境上下文。popHostContext(workInProgress);// 獲取根應用節點const rootContainerInstance = getRootHostContainer();const type = workInProgress.type;// 更新if (current !== null && workInProgress.stateNode != null) {// 突變模式if (supportsMutation) {const oldProps = current.memoizedProps;if (oldProps !== newProps) {// 標記更新markUpdate(workInProgress);}} else {updateHostComponent(current,workInProgress,type,newProps,renderLanes,);}} else {// 初始化if (!newProps) {if (workInProgress.stateNode === null) {throw new Error('We must have new props for new mounts. This error is likely ' +'caused by a bug in React. Please file an issue.',);}// This can happen when we abort work.bubbleProperties(workInProgress);return null;}// 獲取上下文const currentHostContext = getHostContext();const wasHydrated = popHydrationState(workInProgress);let instance: Instance;// 服務端渲染if (wasHydrated) {// prepareToHydrateHostInstance(workInProgress, currentHostContext);// // 復用現有 DOM 節點,避免重新創建。// instance = workInProgress.stateNode;} else {// 客戶端渲染// 通過 resolveSingletonInstance 創建單例實例,并標記更新。instance = resolveSingletonInstance(type,newProps,rootContainerInstance,currentHostContext,true,);workInProgress.stateNode = instance;markUpdate(workInProgress);}}// 屬性冒泡,將子節點的狀態(如副作用標志)向上傳播到父節點。bubbleProperties(workInProgress);// 結束當前 Fiber 的處理return null;}// Fall through
      }
      

      工具函數之 resolveSingletonInstance

      resolveSingletonInstance 是 React 內部用于獲取或創建單例 DOM 元素的核心函數,專門處理那些在文檔中必須唯一存在且不能被 React 直接創建的特殊元素(如 <html><head><body>)。

      function resolveSingletonInstance(type: string,props: Props,rootContainerInstance: Container,hostContext: HostContext,validateDOMNestingDev: boolean,
      ): Instance {// 獲取document對象const ownerDocument = getOwnerDocumentFromRootContainer(rootContainerInstance,);switch (type) {case 'html': {const documentElement = ownerDocument.documentElement;if (!documentElement) {throw new Error('React expected an <html> element (document.documentElement) to exist in the Document but one was' +' not found. React never removes the documentElement for any Document it renders into so' +' the cause is likely in some other script running on this page.',);}return documentElement;}case 'head': {const head = ownerDocument.head;if (!head) {throw new Error('React expected a <head> element (document.head) to exist in the Document but one was' +' not found. React never removes the head for any Document it renders into so' +' the cause is likely in some other script running on this page.',);}return head;}case 'body': {const body = ownerDocument.body;if (!body) {throw new Error('React expected a <body> element (document.body) to exist in the Document but one was' +' not found. React never removes the body for any Document it renders into so' +' the cause is likely in some other script running on this page.',);}return body;}default: {throw new Error('resolveSingletonInstance was called with an element type that is not supported. This is a bug in React.',);}}
      }

      <Tag>HostComponent

      React 處理 HostComponent(如 DOM 元素)的核心邏輯,主要負責創建或更新實際的 DOM 節點。它根據節點是否已存在、是否來自服務端渲染水合等情況,選擇不同的處理路徑,并處理特殊屬性(如自動聚焦)和預加載邏輯。

      case HostComponent: {// 退出當前宿主環境上下文棧popHostContext(workInProgress);// 獲取組件類型,類如div,spanconst type = workInProgress.type;// 更新已存在的 DOM 節點if (current !== null && workInProgress.stateNode != null) {// 調用 updateHostComponent 更新 DOM 屬性(如 className、style)。處理事件監聽器的添加 / 移除。updateHostComponent(current,workInProgress,type,newProps,renderLanes,);// 首次渲染或新增} else {if (!newProps) {// 錯誤處理:新節點必須有 propsif (workInProgress.stateNode === null) {throw new Error('We must have new props for new mounts. This error is likely ' +'caused by a bug in React. Please file an issue.',);}// This can happen when we abort work.bubbleProperties(workInProgress);return null;}const currentHostContext = getHostContext();const wasHydrated = popHydrationState(workInProgress);if (wasHydrated) {// prepareToHydrateHostInstance(workInProgress, currentHostContext);} else {// 純客戶端渲染邏輯const rootContainerInstance = getRootHostContainer();// 調用 createInstance 創建新 DOM 元素。const instance = createInstance(type,newProps,rootContainerInstance,currentHostContext,workInProgress,);markCloned(workInProgress);// 通過 appendAllChildren 添加子元素。appendAllChildren(instance, workInProgress, false, false);workInProgress.stateNode = instance;if (finalizeInitialChildren(instance,type,newProps,currentHostContext,)) {markUpdate(workInProgress);}}}// 屬性冒泡bubbleProperties(workInProgress);// 預加載preloadInstanceAndSuspendIfNeeded(workInProgress,workInProgress.type,workInProgress.pendingProps,renderLanes,);return null;
      }

      updateHostComponent

      updateHostComponent 是 React 處理宿主組件(如 DOM 元素)更新的核心函數,根據渲染模式(突變模式或持久化模式)選擇不同的更新策略。在突變模式下,直接標記節點更新;在持久化模式下,通過克隆實例實現無突變更新,并支持狀態保留。

      function updateHostComponent(current: Fiber,workInProgress: Fiber,type: Type,newProps: Props,renderLanes: Lanes,
      ) {// 突變模式下的處理(supportsMutation)if (supportsMutation) {const oldProps = current.memoizedProps;// 比較新舊屬性引用是否相同(淺比較)。if (oldProps === newProps) {return;}// 標記節點為更新狀態markUpdate(workInProgress);// 持久化模式下的處理(supportsPersistence)} else if (supportsPersistence) {const currentInstance = current.stateNode;const oldProps = current.memoizedProps;// 通過 doesRequireClone 檢查節點是否需要克隆。const requiresClone = doesRequireClone(current, workInProgress);if (!requiresClone && oldProps === newProps) {workInProgress.stateNode = currentInstance;return;}const currentHostContext = getHostContext();let newChildSet = null;if (requiresClone && passChildrenWhenCloningPersistedNodes) {markCloned(workInProgress);newChildSet = createContainerChildSet();// If children might have changed, we have to add them all to the set.appendAllChildrenToContainer(newChildSet,workInProgress,/* needsVisibilityToggle */ false,/* isHidden */ false,);}// 調用 cloneInstance 創建新實例,保留舊狀態。const newInstance = cloneInstance(currentInstance,type,oldProps,newProps,!requiresClone,newChildSet,);if (newInstance === currentInstance) {// 無需變更,復用workInProgress.stateNode = currentInstance;return;} else {// 標記為克隆節點markCloned(workInProgress);}// 處理特殊屬性(如自動聚焦)if (finalizeInitialChildren(newInstance, type, newProps, currentHostContext)) {markUpdate(workInProgress);}// 更新子節點workInProgress.stateNode = newInstance;if (!requiresClone) {if (!enablePersistedModeClonedFlag) {markUpdate(workInProgress);}} else if (!passChildrenWhenCloningPersistedNodes) {// If children have changed, we have to add them all to the set.appendAllChildren(newInstance,workInProgress,/* needsVisibilityToggle */ false,/* isHidden */ false,);}}
      }

      createInstance

      createInstance 方法,用于創建虛擬 DOM 元素的實例。該方法生成一個包含元素類型、屬性和子節點信息的對象,并處理特殊屬性(如 hiddensrc)和文本內容。通過不可枚舉屬性存儲內部狀態,確保這些信息不會暴露給外部代碼。

      const sharedHostConfig = {createInstance(type: string,//元素的類型props: Props,// 傳遞給元素的屬性對象。rootContainerInstance: Container,// 根容器實例,即渲染的目標容器。hostContext: HostContext,// 當前渲染的宿主環境上下文。internalInstanceHandle: Object,// 指向 React 內部 Fiber 節點的引用。): Instance {if (type === 'errorInCompletePhase') {throw new Error('Error in host config.');}// 實例結構const inst = {id: instanceCounter++,type: type,children: [],parent: -1,// shouldSetTextContent:判斷是否應將子節點作為文本內容處理。text: shouldSetTextContent(type, props)? // eslint-disable-next-line react-internal/safe-string-coercion// computeText:處理文本內容(可能包括轉義、格式化等)。computeText((props.children: any) + '', hostContext): null,prop: props.prop,hidden: !!props.hidden,context: hostContext,};// 為 suspensey-thing 類型的元素添加 src 屬性。if (type === 'suspensey-thing' && typeof props.src === 'string') {inst.src = props.src;}// Hide from unit tests// 將 id、parent、text 等屬性設為不可枚舉。// 防止這些內部狀態在 for...in 循環或 JSON.stringify 中暴露。Object.defineProperty(inst, 'id', {value: inst.id, enumerable: false});Object.defineProperty(inst, 'parent', {value: inst.parent,enumerable: false,});Object.defineProperty(inst, 'text', {value: inst.text,enumerable: false,});Object.defineProperty(inst, 'context', {value: inst.context,enumerable: false,});Object.defineProperty(inst, 'fiber', {value: internalInstanceHandle,enumerable: false,});return inst;},
      }

      關鍵屬性

      • id:唯一標識,用于內部跟蹤。
      • type:元素類型(如 divspan)。
      • children:子節點數組。
      • text:文本內容(如果適用)。
      • hidden:是否隱藏(基于 props.hidden)。
      const inst = {id: instanceCounter++,type: type,children: [],parent: -1,// shouldSetTextContent:判斷是否應將子節點作為文本內容處理。text: shouldSetTextContent(type, props)? // eslint-disable-next-line react-internal/safe-string-coercion// computeText:處理文本內容(可能包括轉義、格式化等)。computeText((props.children: any) + '', hostContext): null,prop: props.prop,hidden: !!props.hidden,context: hostContext,
      };

      工具函數之?shouldSetTextContent?

      function shouldSetTextContent(type: string, props: Props): boolean {if (type === 'errorInBeginPhase') {throw new Error('Error in host config.');}return (typeof props.children === 'string' ||typeof props.children === 'number' ||typeof props.children === 'bigint');
      }
      

      工具函數之?computeText?

      computeText 是一個文本處理函數,用于根據宿主環境上下文決定是否轉換文本大小寫。當上下文為 UPPERCASE_CONTEXT 時,將文本轉換為大寫;否則保持原文。?

      
      function computeText(rawText, hostContext) {return hostContext === UPPERCASE_CONTEXT ? rawText.toUpperCase() : rawText;
      }const UPPERCASE_CONTEXT = {};

      工具函數之 finalizeInitialChildren

      finalizeInitialChildren?函數主要用于完成元素初始化后的最終處理。

      它執行以下核心操作:

      1. 通過 setInitialProperties 設置元素的初始屬性(如 classNamestyle)。
      2. 根據元素類型判斷是否需要在渲染后執行副作用操作(如自動聚焦、圖片預加載)。
      3. 返回布爾值,指示該元素是否需要在提交階段(commit phase)執行額外的副作用。
      function finalizeInitialChildren(domElement: Instance,type: string,props: Props,hostContext: HostContext,
      ): boolean {setInitialProperties(domElement, type, props);switch (type) {case 'button':case 'input':case 'select':case 'textarea':return !!props.autoFocus;case 'img':return true;default:return false;}
      }

      工具函數之 appendAllChildren

      appendAllChildren 函數用于將 Fiber 樹中的所有子節點掛載到父 DOM 節點上。它通過深度優先遍歷 Fiber 樹,將真實 DOM 節點(如 HostComponentHostText)按正確順序添加到父容器中。該函數針對不同渲染模式(突變模式和持久化模式)進行了優化。

      處理過程:

      一、突變模式

      1. 處理當前子節點
        1. 如果節點tag是 HostComponent 或者 HostText,直接將 HostComponent(DOM 元素)或 HostText(文本節點)直接添加到父容器。
        2. 如果節點tag是?HostPortal,不做處理。(Portal 節點不直接添加到父容器,而是通過 Portal 機制掛載到其他容器)
        3. 如果當前子節點有子節點,則進入遞歸處理(則為下面的第2點)
      2. 遞歸處理子節點
      3. 如果當前子節點正是正在處理的fiber(workInProgress),則退出當前循環。
      4. 回溯或處理兄弟節點

      二、持久化模式

      1. 處理當前子節點
        1. 如果節點tag是 HostComponent ,當需要隱藏時克隆節點并應用隱藏樣式直接,然后將克隆實例 instance 直接添加到父容器。
        2. 如果節點tag是 HostText ,當需要隱藏時克隆節點并應用隱藏樣式直接,然后將克隆實例 instance 直接添加到父容器。
        3. 如果節點tag是?HostPortal,不做處理。(Portal 節點不直接添加到父容器,而是通過 Portal 機制掛載到其他容器)
        4. 如果節點tag是?OffscreenComponent,處理其子節點與子節點的引用關系,調用appendAllChildren遞歸處理子節點。
        5. 如果當前子節點有子節點,則進入遞歸處理(則為下面的第2點)
      2. 遞歸處理子節點
      3. 如果當前子節點正是正在處理的fiber(workInProgress),則退出當前循環。
      4. 回溯或處理兄弟節點
      function appendAllChildren(parent: Instance,// 指定子節點要掛載到的父容器。workInProgress: Fiber,// 當前正在處理的 Fiber 節點,作為遍歷起點。needsVisibilityToggle: boolean, //指示是否需要根據 isHidden 參數調整子節點的可見性。isHidden: boolean, // 當 needsVisibilityToggle 為 true 時,決定子節點是否應被隱藏。
      ) {// 突變模式處理(supportsMutation)if (supportsMutation) {let node = workInProgress.child;while (node !== null) {// 處理當前節點if (node.tag === HostComponent || node.tag === HostText) {// 將 HostComponent(DOM 元素)或 HostText(文本節點)直接添加到父容器。appendInitialChild(parent, node.stateNode);} else if (node.tag === HostPortal ||(supportsSingletons ? node.tag === HostSingleton : false)) {// Portal 節點不直接添加到父容器,而是通過 Portal 機制掛載到其他容器// 遞歸處理子節點} else if (node.child !== null) {node.child.return = node;node = node.child;continue;}if (node === workInProgress) {return;}//  回溯或處理兄弟節點while (node.sibling === null) {if (node.return === null || node.return === workInProgress) {return;}node = node.return;}node.sibling.return = node.return;node = node.sibling;}// 持久化模式處理(supportsPersistence)} else if (supportsPersistence) {// We only have the top Fiber that was created but we need recurse down its// children to find all the terminal nodes.let node = workInProgress.child;while (node !== null) {if (node.tag === HostComponent) {let instance = node.stateNode;if (needsVisibilityToggle && isHidden) {// 當節點位于超時的 Suspense 邊界內時,克隆節點并應用隱藏樣式。const props = node.memoizedProps;const type = node.type;instance = cloneHiddenInstance(instance, type, props);}//將 instance 直接添加到父容器。appendInitialChild(parent, instance);} else if (node.tag === HostText) {let instance = node.stateNode;if (needsVisibilityToggle && isHidden) {const text = node.memoizedProps;instance = cloneHiddenTextInstance(instance, text);}appendInitialChild(parent, instance);} else if (node.tag === HostPortal) {// Portal 節點不直接添加到父容器,而是通過 Portal 機制掛載到其他容器} else if (node.tag === OffscreenComponent &&node.memoizedState !== null) {const child = node.child;if (child !== null) {child.return = node;}appendAllChildren(parent,node,/* needsVisibilityToggle */ true,/* isHidden */ true,);// 遞歸處理子節點} else if (node.child !== null) {node.child.return = node;node = node.child;continue;}if (node === workInProgress) {return;}// 回溯或處理兄弟節點while (node.sibling === null) {if (node.return === null || node.return === workInProgress) {return;}node = node.return;}node.sibling.return = node.return;node = node.sibling;}}
      }
      

      ?工具函數之?appendInitialChild

      function appendInitialChild(parentInstance: Instance,child: Instance | TextInstance,
      ): void {parentInstance.appendChild(child);
      }

      ?工具函數之?cloneHiddenInstance

      cloneHiddenInstance 方法,用于創建一個隱藏版本的 DOM 元素實例。該方法在需要臨時隱藏元素但保留其結構和狀態時使用。

      const hostConfig = useMutation ? {       cloneHiddenInstance(instance: Instance,type: string,props: Props,): Instance {const clone = cloneInstance(instance, type, props, props, true, null);clone.hidden = true;return clone;},
      }

      工具函數之 cloneInstance

      cloneInstance 是 React 內部用于克隆 DOM 元素實例的函數,主要用于在不改變原始實例的情況下創建一個具有新屬性的副本

      function cloneInstance(instance: Instance,type: string,oldProps: Props,newProps: Props,keepChildren: boolean,children: ?$ReadOnlyArray<Instance>,
      ): Instance {// 實例克隆核心邏輯const clone = {id: instance.id,type: type,parent: instance.parent,children: keepChildren ? instance.children : children ?? [],text: shouldSetTextContent(type, newProps)? computeText((newProps.children: any) + '', instance.context): null,prop: newProps.prop,hidden: !!newProps.hidden,context: instance.context,};// 當元素類型為 suspensey-thing 且新屬性包含 src 時,添加 src 屬性到克隆實例。if (type === 'suspensey-thing' && typeof newProps.src === 'string') {clone.src = newProps.src;}// 不可枚舉屬性設置// 將關鍵內部屬性設為不可枚舉,避免在遍歷或序列化時暴露。
      // 保持與原始實例的行為一致性。Object.defineProperty(clone, 'id', {value: clone.id,enumerable: false,});Object.defineProperty(clone, 'parent', {value: clone.parent,enumerable: false,});Object.defineProperty(clone, 'text', {value: clone.text,enumerable: false,});Object.defineProperty(clone, 'context', {value: clone.context,enumerable: false,});hostCloneCounter++;return clone;
      }

      工具函數之 cloneHiddenTextInstance

      cloneHiddenTextInstance 方法,專門用于克隆文本節點并將其標記為隱藏狀態。用在處理需要臨時隱藏文本內容但保留其結構和上下文的場景時。

      const hostConfig = useMutation ?  {cloneHiddenTextInstance(instance: TextInstance,text: string,): TextInstance {const clone = {text: instance.text,id: instance.id,parent: instance.parent,hidden: true,context: instance.context,};// Hide from unit testsObject.defineProperty(clone, 'id', {value: clone.id,enumerable: false,});Object.defineProperty(clone, 'parent', {value: clone.parent,enumerable: false,});Object.defineProperty(clone, 'context', {value: clone.context,enumerable: false,});return clone;},
      }

      preloadInstanceAndSuspendIfNeeded

      preloadInstanceAndSuspendIfNeeded?函數負責在元素實例化階段預加載資源并決定是否需要掛起渲染。

      它通過以下步驟實現精細控制:

      1. 判斷元素是否可能觸發提交階段的掛起(如包含異步資源)。
      2. 嘗試預加載資源并檢查就緒狀態。
      3. 根據資源狀態和屏幕過渡策略,決定是繼續渲染、掛起并保持當前屏幕,還是立即掛起并顯示 fallback。
      function preloadInstanceAndSuspendIfNeeded(workInProgress: Fiber,type: Type,props: Props,renderLanes: Lanes,
      ) {if (!maySuspendCommit(type, props)) {// MaySuspendCommit:表示該 Fiber 節點可能會暫停提交操作。在 React 的并發模式下,渲染過程可能會被暫停和恢復workInProgress.flags &= ~MaySuspendCommit;return;}workInProgress.flags |= MaySuspendCommit;const isReady = preloadInstance(type, props);if (!isReady) {if (shouldRemainOnPreviousScreen()) {workInProgress.flags |= ShouldSuspendCommit;} else {suspendCommit();}}
      }

      工具函數之 preloadResource

      preloadResource 是一個用于資源預加載控制的函數,主要決定特定資源是否需要暫停渲染(suspend)。核心邏輯是:當資源類型為樣式表(stylesheet)且處于未加載狀態時,函數返回 false 觸發渲染暫停;否則返回 true 繼續渲染。

      function preloadResource(resource: Resource): boolean {if (resource.type === 'stylesheet' &&(resource.state.loading & Settled) === NotLoaded) {// Return false to indicate this resource should suspendreturn false;}// Return true to indicate this resource should not suspendreturn true;
      }

      <Tag>HostText

      React 處理 HostText 類型節點(即文本節點)的核心邏輯,主要負責更新或創建文本節點實例。它會根據節點是否已存在、是否來自服務端渲染水合等情況,選擇不同的處理路徑,確保文本內容正確地反映到 DOM 中。

      case HostText: {// 獲取新舊文本內容const newText = newProps;// 更新if (current && workInProgress.stateNode != null) {const oldText = current.memoizedProps;// 調用 updateHostText 更新現有文本節點內容(如 setTextContent)。updateHostText(current, workInProgress, oldText, newText);// 首次渲染} else {// 處理新創建的文本節點if (typeof newText !== 'string') {if (workInProgress.stateNode === null) {throw new Error('We must have new props for new mounts. This error is likely ' +'caused by a bug in React. Please file an issue.',);}// This can happen when we abort work.}// 獲取當前渲染的根容器(如 DOM 中的 root 節點)。const rootContainerInstance = getRootHostContainer();// 獲取宿主環境上下文const currentHostContext = getHostContext();// 處理服務端渲染水合狀態const wasHydrated = popHydrationState(workInProgress);// 檢查當前節點是否來自服務端渲染的 HTML。if (wasHydrated) {// prepareToHydrateHostTextInstance(workInProgress);} else {// 添加Cloned標記markCloned(workInProgress);// 創建文本實例workInProgress.stateNode = createTextInstance(newText,rootContainerInstance,currentHostContext,workInProgress,);}}// 冒泡屬性與完成處理bubbleProperties(workInProgress);return null;
      }

      updateHostText

      updateHostText 是 React 處理文本節點更新的核心函數,根據渲染模式(突變模式或持久化模式)選擇不同的更新策略。當文本內容發生變化時,突變模式直接標記更新,而持久化模式則創建新的文本實例并標記克隆。這一機制確保了在不同渲染模式下文本更新的高效性和正確性。

      function updateHostText(current: Fiber,workInProgress: Fiber,oldText: string,newText: string,
      ) {// 突變模式下的處理(supportsMutation)if (supportsMutation) {// If the text differs, mark it as an update. All the work in done in commitWork.// 當新舊文本內容不一致時,標記節點為 Update。if (oldText !== newText) {markUpdate(workInProgress);}// 持久化模式下的處理(supportsPersistence)} else if (supportsPersistence) {if (oldText !== newText) {// If the text content differs, we'll create a new text instance for it.const rootContainerInstance = getRootHostContainer();const currentHostContext = getHostContext();markCloned(workInProgress);// 創建新的文本實例workInProgress.stateNode = createTextInstance(newText,rootContainerInstance,currentHostContext,workInProgress,);// 確保父節點知道子節點已變更if (!enablePersistedModeClonedFlag) {// We'll have to mark it as having an effect, even though we won't use the effect for anything.// This lets the parents know that at least one of their children has changed.markUpdate(workInProgress);}} else {// 文本未變化,復用現有實例workInProgress.stateNode = current.stateNode;}}
      }

      工具函數之?markUpdate

      function markUpdate(workInProgress: Fiber) {workInProgress.flags |= Update;
      }

      工具函數之?markCloned

      function markCloned(workInProgress: Fiber) {if (supportsPersistence && enablePersistedModeClonedFlag) {// 添加 Cloned 標志(flags |= Cloned)。workInProgress.flags |= Cloned;}
      }

      工具函數之?getRootHostContainer

      getRootHostContainer?是 React 渲染系統中的基礎函數,用于獲取當前渲染上下文的根宿主容器。在瀏覽器環境中,這通常對應于?ReactDOM.render?或?ReactDOM.createRoot?指定的 DOM 節點(如?<div id="root"></div>)。

      function getRootHostContainer(): Container {const rootInstance = requiredContext(rootInstanceStackCursor.current);return rootInstance;
      }
      const rootInstanceStackCursor: StackCursor<Container | null> = createCursor(null);
      function createCursor<T>(defaultValue: T): StackCursor<T> {return {current: defaultValue,};
      }
      function requiredContext<Value>(c: Value | null): Value {return (c: any);
      }

      ?工具函數之?getHostContext

      getHostContext() 是 React 渲染系統中的核心函數,用于獲取當前宿主環境的上下文信息。這些信息包括命名空間(如 HTML/SVG)、樣式作用域、容器配置等,是正確創建和渲染 DOM 元素的關鍵依據。通過維護一個上下文棧,React 能夠在嵌套渲染(如 SVG 內部元素)時動態切換環境配置,確保元素正確渲染。

      function getHostContext(): HostContext {const context = requiredContext(contextStackCursor.current);return context;
      }
      const contextStackCursor: StackCursor<Object> =createCursor(emptyContextObject);const emptyContextObject: {} = {};

      createTextInstance

      ?createTextInstance?是 React 渲染系統中用于創建文本節點的核心函數。它通過宿主環境(如瀏覽器 DOM)提供的 API 創建實際的文本節點,并建立該節點與 React 內部 Fiber 節點的映射關系。這一過程是將虛擬 DOM 轉換為真實 DOM 的關鍵步驟

      function createTextInstance(text: string,rootContainerInstance: Container,hostContext: HostContext,internalInstanceHandle: Object,
      ): TextInstance {// 創建新文本節點,調用 document.createTextNode(text) 創建實際的文本節點。const textNode: TextInstance = getOwnerDocumentFromRootContainer(rootContainerInstance,).createTextNode(text);// 建立 Fiber 節點與 DOM 節點的映射precacheFiberNode(internalInstanceHandle, textNode);return textNode;
      }

      ?工具函數之?getOwnerDocumentFromRootContainer

      獲取根容器所屬的 document 對象。

      function getOwnerDocumentFromRootContainer(rootContainerElement: Element | Document | DocumentFragment,
      ): Document {return rootContainerElement.nodeType === DOCUMENT_NODE? (rootContainerElement: any): rootContainerElement.ownerDocument;
      }

      工具函數之?precacheFiberNode

      建立 Fiber 節點與 DOM 節點的映射?

      function precacheFiberNode(hostInst: Fiber,node: Instance | TextInstance | SuspenseInstance | ReactScopeInstance,
      ): void {(node: any)[internalInstanceKey] = hostInst;
      }
      const randomKey = Math.random().toString(36).slice(2);
      const internalInstanceKey = '__reactFiber$' + randomKey;

      <Tag>HostPortal

      處理 React 中 HostPortal 類型的 Fiber 節點,用于管理通過 ReactDOM.createPortal 創建的 Portal 組件。Portal 允許將子組件渲染到 DOM 樹的不同位置(如獨立的模態框、懸浮層),但保持與父組件的上下文關系。

      執行過程:

      1. 彈出 Portal 容器的上下文
      2. 更新 Portal 容器的狀態
      3. 準備 Portal 掛載(首次渲染時)
      4. 冒泡屬性以傳播副作用和狀態
      case HostPortal:
      // 從上下文棧中彈出當前 Portal 的容器信息。popHostContainer(workInProgress);// 比較新舊 Portal 容器的屬性差異。標記需要執行的副作用(如屬性更新、事件綁定)。updateHostContainer(current, workInProgress);// 首次掛載處理if (current === null) {//確保目標容器存在且可訪問。注冊 Portal 相關的事件處理(如點擊穿透)。應用初始樣式或動畫。preparePortalMount(workInProgress.stateNode.containerInfo);}// 屬性冒泡,將 Portal 子樹的狀態(如副作用標志、優先級)傳播到父節點。bubbleProperties(workInProgress);return null;

      工具函數之?preparePortalMount?

      function preparePortalMount(portalInstance: Instance): void {listenToAllSupportedEvents(portalInstance);
      }

      工具函數之?listenToAllSupportedEvents?

      主要功能是為 React 應用的指定容器添加對所有支持的原生事件的監聽。它會對事件監聽進行去重處理,避免重復添加相同的事件監聽器。同時,對于 selectionchange 事件會進行特殊處理,因為該事件不會冒泡,需要綁定到 document 對象上。?(詳細的后續寫一篇記錄react合成事件)

      function listenToAllSupportedEvents(rootContainerElement: EventTarget) {// 檢查 rootContainerElement 是否已經添加了事件監聽器。如果沒有,則將 listeningMarker 作為屬性添加到 rootContainerElement 上,并將其值設為 true,表示已經添加了事件監聽器。if (!(rootContainerElement: any)[listeningMarker]) {(rootContainerElement: any)[listeningMarker] = true;// allNativeEvents 是一個集合,包含了 React 支持的所有原生事件。// 遍歷所有支持的原生事件allNativeEvents.forEach(domEventName => {if (domEventName !== 'selectionchange') {if (!nonDelegatedEvents.has(domEventName)) {listenToNativeEvent(domEventName, false, rootContainerElement);}listenToNativeEvent(domEventName, true, rootContainerElement);}});// 獲取頂層document對象const ownerDocument =(rootContainerElement: any).nodeType === DOCUMENT_NODE? rootContainerElement: (rootContainerElement: any).ownerDocument;if (ownerDocument !== null) {// The selectionchange event also needs deduplication// but it is attached to the document.if (!(ownerDocument: any)[listeningMarker]) {(ownerDocument: any)[listeningMarker] = true;listenToNativeEvent('selectionchange', false, ownerDocument);}}}
      }

      全局常量(根節點狀態)

      ?React 渲染根節點(Root)的狀態機,用于表示整個渲染過程中可能處于的不同階段和結果。

      type RootExitStatus = 0 | 1 | 2 | 3 | 4 | 5 | 6;
      const RootInProgress = 0; // 根節點正在進行渲染
      const RootFatalErrored = 1; // 渲染過程中發生致命錯誤,無法恢復。
      const RootErrored = 2; //渲染過程中發生可恢復的錯誤。
      const RootSuspended = 3; // 渲染被掛起,等待異步資源(如數據或代碼)。
      const RootSuspendedWithDelay = 4; // 渲染被掛起,但設置了延遲顯示加載狀態。
      const RootCompleted = 5; // 渲染成功完成,所有工作已提交到 DOM。
      const RootDidNotComplete = 6; // 渲染未完成,可能被更高優先級的更新中斷。

      ?全局常量(組件類型)

      ?React 內部用于標識不同類型組件和節點的常量(稱為?FiberTag)。每個常量對應一種特定的組件或節點類型。

      export const FunctionComponent = 0;
      export const ClassComponent = 1;export const HostRoot = 3; // Root of a host tree. Could be nested inside another node.
      export const HostPortal = 4; // A subtree. Could be an entry point to a different renderer.
      export const HostComponent = 5;
      export const HostText = 6;export const Fragment = 7;
      export const Mode = 8;
      export const ContextConsumer = 9;
      export const ContextProvider = 10;
      export const ForwardRef = 11;
      export const Profiler = 12;export const SuspenseComponent = 13;export const MemoComponent = 14;
      export const SimpleMemoComponent = 15;
      export const LazyComponent = 16;export const IncompleteClassComponent = 17;
      export const DehydratedFragment = 18;export const SuspenseListComponent = 19;
      export const ScopeComponent = 21;
      export const OffscreenComponent = 22;
      export const LegacyHiddenComponent = 23;
      export const CacheComponent = 24;
      export const TracingMarkerComponent = 25;export const HostHoistable = 26;
      export const HostSingleton = 27;export const IncompleteFunctionComponent = 28;
      export const Throw = 29;

      ?全局常量(節點的狀態和操作位掩碼)

      標記節點狀態和操作的位掩碼常量(Flags)。每個標志都是一個二進制值,通過位運算可以高效地組合、檢查和修改這些標志。

      // 無操作(初始狀態)。
      const NoFlags = /*                      */ 0b0000000000000000000000000000;
      // 組件已執行工作(用于優化)。
      const PerformedWork = /*                */ 0b0000000000000000000000000001;
      // 需要插入或移動 DOM 節點。
      const Placement = /*                    */ 0b0000000000000000000000000010;
      // 組件捕獲到錯誤(用于錯誤邊界)。
      const DidCapture = /*                   */ 0b0000000000000000000010000000;
      // 需要重置節點內容(如文本節點內容完全改變)。
      const Hydrating = /*                    */ 0b0000000000000001000000000000;// You can change the rest (and add more).
      // 需要更新 DOM 節點屬性(如 props 變化)。
      const Update = /*                       */ 0b0000000000000000000000000100;
      // Fiber 被克隆(如列表重排序時復用節點)。
      const Cloned = /*                       */ 0b0000000000000000000000001000;// 需要刪除子節點。
      const ChildDeletion = /*                */ 0b0000000000000000000000010000;
      // 需要重置節點內容(如文本節點內容完全改變)。
      const ContentReset = /*                 */ 0b0000000000000000000000100000;
      // 需要執行回調(如 useEffect、useLayoutEffect)。
      const Callback = /*                     */ 0b0000000000000000000001000000;
      /* Used by DidCapture:                            0b0000000000000000000010000000; */// 強制客戶端渲染(如 SSR 水合失敗)。const ForceClientRender = /*            */ 0b0000000000000000000100000000;
      // 需要處理 ref 關聯或解關聯。const Ref = /*                          */ 0b0000000000000000001000000000;
      // 需要捕獲 DOM 快照(如 getSnapshotBeforeUpdate)。const Snapshot = /*                     */ 0b0000000000000000010000000000;
      // 表示存在被動副作用(如 useEffect),需要異步執行。const Passive = /*                      */ 0b0000000000000000100000000000;
      /* Used by Hydrating:                             0b0000000000000001000000000000; */// 組件可見性變化(如 Suspense 顯示 / 隱藏)。const Visibility = /*                   */ 0b0000000000000010000000000000;
      // 狀態一致性標記(用于并發模式)。const StoreConsistency = /*             */ 0b0000000000000100000000000000;

      全局常量

      1. RefStatic:用于標記與 ref 相關的靜態狀態。在 React 中,ref 用于訪問 DOM 節點或組件實例,這個標志可能表示 ref 相關的操作或狀態是靜態的,不需要在每次渲染時重新處理。
      2. LayoutStatic:表示與布局相關的靜態狀態。布局操作可能涉及到元素的位置、大小等信息,這個標志可能用于指示某些布局信息在渲染過程中是靜態的,不需要頻繁更新。
      3. PassiveStatic:與被動副作用相關的靜態狀態。被動副作用通常是指那些在渲染完成后異步執行的副作用,如 useEffect 鉤子中的某些操作,這個標志可能表示這些副作用的狀態是靜態的。
      4. MaySuspendCommit:表示該 Fiber 節點可能會暫停提交操作。在 React 的并發模式下,渲染過程可能會被暫停和恢復,這個標志用于標記那些可能會導致提交操作暫停的節點。
      const StaticMask =LayoutStatic | PassiveStatic | RefStatic | MaySuspendCommit;const RefStatic = /*                    */ 0b0000001000000000000000000000;
      const LayoutStatic = /*                 */ 0b0000010000000000000000000000;
      const PassiveStatic = /*                */ 0b0000100000000000000000000000;
      const MaySuspendCommit = /*             */ 0b0001000000000000000000000000;

      本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
      如若轉載,請注明出處:http://www.pswp.cn/diannao/84288.shtml
      繁體地址,請注明出處:http://hk.pswp.cn/diannao/84288.shtml
      英文地址,請注明出處:http://en.pswp.cn/diannao/84288.shtml

      如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

      相關文章

      c# 解碼 encodeURIComponent

      在C#中&#xff0c;如果你需要解碼由encodeURIComponent方法編碼的URL&#xff0c;你可以使用System.Web命名空間中的HttpUtility.UrlDecode方法。這個方法可以處理由JavaScript的encodeURIComponent方法編碼的字符串。 首先&#xff0c;確保你的項目中引用了System.Web命名空…

      Python學習心得:代碼森林的冒險

      第一章&#xff1a;迷霧中的第一步 林然從未想過自己會與代碼結緣。那是一個平淡的周六清晨&#xff0c;陽光穿過窗簾&#xff0c;灑在她那臺老舊的筆記本電腦上。屏幕上&#xff0c;Python的安裝界面靜靜地等待著她的決定。她是一個文科生&#xff0c;大學主修社會學&#xf…

      展示了一個三軸(X, Y, Z)坐標系!

      等軸測投影”&#xff08;isometric projection&#xff09;風格的手繪風格三維圖&#xff0c;即三條坐標軸&#xff08;x?, x?, x?&#xff09;看起來彼此垂直、等角分布&#xff08;通常是 120 夾角&#xff09;&#xff0c;它是常見于教材和數學書籍的 “假三維”表示法。…

      計算機網絡 - 2.基礎協議

      1.TCP協議 1.TCP(Transmission Control Protocol):傳輸控制協議2.TCP協議是一種面向連接的、可靠的、 基于字節流的傳輸層通信協議 1.面向連接:兩個使用TCP協議的應用(通常一個客戶和一個服務器)在彼此交換數據包之前必須先建立一個TCP連接2.可靠的 1.數據傳輸之前都要建立…

      前端之vue3創建基本工程,基本登錄、注冊等功能的完整過程

      此文也是為了做一個基本學習用的vue3創建項目的過程&#xff0c;包含基本的登錄頁面、登出頁面、基本的router跳轉、axios調用、登錄驗證等內容。與項目&#xff1a; https://gitee.com/rainpet/java-web-demo/tree/master/spring-security01 可以配套使用。 如下為主要過程。 …

      如果有三個服務實例部署在三臺不同的服務器上,這三個服務實例的本地緩存,是存儲一模一樣的數據?還是各自只存一部分?

      ? 答案是&#xff1a;通常每個服務實例都會獨立地緩存它自己訪問過的數據&#xff0c;這些數據可能是相同的&#xff0c;也可能是不同的&#xff0c;取決于請求的內容。 &#x1f4cc; 舉個例子說明 假設你有一個商品詳情頁的服務&#xff0c;部署了 3 個服務實例&#xff08…

      九州未來十三載:開源賦能 智啟未來

      2012年&#xff0c;九州未來以“開源賦能云邊變革”為使命&#xff0c;開啟中國開放云邊基礎架構服務的探索之路。十三載堅守深耕&#xff0c;我們始終以開源為翼&#xff0c;以算力為基&#xff0c;在科技浪潮中砥礪前行&#xff0c;見證并推動著AI時代的算力變革。 堅守初心丨…

      Axure項目實戰:智慧運輸平臺后臺管理端-訂單管理1(多級交互)

      親愛的小伙伴,在您瀏覽之前,煩請關注一下,在此深表感謝!如有幫助請訂閱專欄! Axure產品經理精品視頻課已登錄CSDN可點擊學習https://edu.csdn.net/course/detail/40420 課程主題:訂單管理 主要內容:條件組合、中繼器篩選、表單跟隨菜單拖動、審批數據互通等 應用場景…

      WebAssembly:開啟跨平臺高性能編程的新時代

      在當今的互聯網時代&#xff0c;Web 應用的復雜性和性能要求越來越高。從簡單的網頁瀏覽到復雜的在線游戲、實時數據處理和圖形渲染&#xff0c;開發者需要一種能夠兼顧性能和兼容性的技術。WebAssembly&#xff08;簡稱 Wasm&#xff09;應運而生&#xff0c;它作為一種新興的…

      大數據治理:理論、實踐與未來展望(二)

      書接上文 文章目錄 七、大數據治理的未來發展趨勢&#xff08;一&#xff09;智能化與自動化&#xff08;二&#xff09;數據隱私與安全的強化&#xff08;三&#xff09;數據治理的云化&#xff08;四&#xff09;數據治理的跨行業合作&#xff08;五&#xff09;數據治理的生…

      計算機視覺與深度學習 | Matlab實現EMD-GWO-SVR、EMD-SVR、GWO-SVR、SVR時間序列預測(完整源碼和數據)

      以下是一個完整的Matlab時間序列預測實現方案,包含EMD-GWO-SVR、EMD-SVR、GWO-SVR和SVR四種方法的對比。代碼包含數據生成、信號分解、優化算法和預測模型實現。 %% 主程序:時間序列預測對比實驗 clc; clear; clearvars; close all;% 生成模擬時間序列數據 rng(1); % 固定隨…

      RabbitMQ核心特性——重試、TTL、死信隊列

      一、重試機制 在消息傳輸過程中&#xff0c;可能遇到各種問題&#xff0c;如網絡故障&#xff0c;服務器不可用等&#xff0c;這些問題可能導致消息處理失敗&#xff0c;因此RabbitMQ提供了重試機制&#xff0c;允許消息處理失敗后重新發送&#xff0c;但是&#xff0c;如果是因…

      MVCC實現原理

      MVCC的基本概念 MVCC&#xff0c;一個數據的多個版本&#xff0c;使得讀寫操作沒有沖突。 在多個事務并發的情況下&#xff0c;確定到底要訪問哪個版本。 MVCC實現原理 MVCC實現依賴于隱式字段&#xff0c;undo log日志&#xff0c;readView 隱式字段 在mysql用戶自定義的…

      湖北理元理律師事務所債務優化方案解析:如何科學規劃還款保障生活質量

      在當前經濟環境下&#xff0c;債務問題已成為困擾許多家庭的重要難題。據相關統計數據顯示&#xff0c;我國個人負債率呈現逐年上升趨勢&#xff0c;如何合理規劃還款、保障基本生活質量成為亟待解決的社會問題。湖北理元理律師事務所基于多年實務經驗&#xff0c;研發出一套科…

      ffmpeg 轉換視頻格式

      使用FFmpeg將視頻轉換為MP4格式的常用命令&#xff1a; ffmpeg -i input.mov -c:v libx264 -crf 23 -c:a aac output.mp4 -i input.avi&#xff1a;指定輸入文件 -c:v libx264&#xff1a;使用H.264視頻編碼器 -crf 23&#xff1a;控制視頻質量&#xff08;范圍18-28&#…

      LLM Tuning

      Lora-Tuning 什么是Lora微調&#xff1f; LoRA&#xff08;Low-Rank Adaptation&#xff09; 是一種參數高效微調方法&#xff08;PEFT, Parameter-Efficient Fine-Tuning&#xff09;&#xff0c;它通過引入低秩矩陣到預訓練模型的權重變換中&#xff0c;實現無需大規模修改…

      實現tdx-hs300-mcp

      文章目錄 項目簡介功能說明使用方法配置說明項目簡介 tdx-hs300-mcp是一個Model Context Protocol (MCP)的服務 功能說明 下載數據自動保存為CSV格式文件使用方法 確保已安裝Python 3.7+和依賴庫: pip install pytdx fastapi uvicorn啟動MCP服務: mcp run MCP.py使用MCP工具…

      《100天精通Python——基礎篇 2025 第20天:Thread類與線程同步機制詳解》

      目錄 一、概念簡單回顧二、Python的線程開發2.1 Thread類2.1.1 線程啟動2.1.2 線程退出2.1.3 線程的傳參2.1.4 threading的屬性和方法2.1.5 Thread實例的屬性和方法2.1.6 start和run方法 2.2 多線程2.3 線程安全2.4 daemon線程2.5 threading.local類2.6 __slots__拓展 三、線程…

      【web應用】前后端分離開源項目聯調運行的過程步驟ruoyi

      文章目錄 ?前言?一、項目運行環境準備?二、數據庫創建&#x1f31f;1、新建數據庫&#x1f31f;2、導入數據腳本 ?三、運行后端項目&#x1f31f;1、打開后端項目&#x1f31f;2、后端項目配置項修改 ?四、運行前端項目VUE3&#x1f31f;1、在IDEA另一個窗口中打開前端項目…

      【深度剖析】三一重工的數字化轉型(下篇1)

      在數字經濟持續發展的背景下,企業數字化轉型方案成為實現轉型的關鍵。不同行業內的企業因轉型動機和路徑的差異,其轉型成效也各異。三一重工作為機械制造行業的領軍企業,較早地實施了數字化轉型,并積累了豐富的經驗。本研究選取三一重工作為案例,通過梳理相關文獻,對其數…