react中的Context

发布时间:2026/8/9 17:05:04
react中的Context 1、createContext创建ReactContext对象。function createContextT(defaultValue: T): ReactContextT { const context: ReactContextT { $$typeof: REACT_CONTEXT_TYPE, _currentValue: defaultValue, _currentValue2: defaultValue, _threadCount: 0, Provider: (null: any), Consumer: (null: any), }; context.Provider { $$typeof: REACT_PROVIDER_TYPE, _context: context, }; let hasWarnedAboutUsingNestedContextConsumers false; let hasWarnedAboutUsingConsumerProvider false; let hasWarnedAboutDisplayNameOnConsumer false; context.Consumer context; return context; }ReactContext定义如下type ReactContextT { $$typeof: Symbol | number, Consumer: ReactContextT, Provider: ReactProviderTypeT, _currentValue: T, _currentValue2: T, _threadCount: number, // DEV only _currentRenderer?: Object | null, _currentRenderer2?: Object | null, // This value may be added by application code // to improve DEV tooling display names displayName?: string, ... };Provider是element对象 $$typeof: REACT_PROVIDER_TYPEConsumer是element对象$$typeof: REACT_CONTEXT_TYPE_currentValue保存传递给 Provider 的value2、beginWork更新操作是在ReactFiberBeginWork.new.js文件中的beginWork函数中如果属性有变更并且tag类型为ContextProvider调用updateContextProvider来更新consumer。function beginWork( current: Fiber | null, workInProgress: Fiber, renderLanes: Lanes, ): Fiber | null { let updateLanes workInProgress.lanes; workInProgress.lanes NoLanes; switch (workInProgress.tag) { case ContextProvider: return updateContextProvider(current, workInProgress, renderLanes); }2.1、updateContextProviderfunction updateContextProvider( current: Fiber | null, workInProgress: Fiber, renderLanes: Lanes, ) { const providerType: ReactProviderTypeany workInProgress.type; const context: ReactContextany providerType._context; const newProps workInProgress.pendingProps; const oldProps workInProgress.memoizedProps; const newValue newProps.value; pushProvider(workInProgress, context, newValue); if (enableLazyContextPropagation) { } else { if (oldProps ! null) { const oldValue oldProps.value; if (is(oldValue, newValue)) { // No change. Bailout early if children are the same. if ( oldProps.children newProps.children !hasLegacyContextChanged() ) { return bailoutOnAlreadyFinishedWork( current, workInProgress, renderLanes, ); } } else { // The context value changed. Search for matching consumers and schedule // them to update. propagateContextChange(workInProgress, context, renderLanes); } } } const newChildren newProps.children; reconcileChildren(current, workInProgress, newChildren, renderLanes); return workInProgress.child; }调用 pushProvider将Provider的value值赋值给context的_currentValue在主渲染情况下或者_currentValue2context的value有变动时调用propagateContextChange进行更新调度子节点更新reconcileChildren2.2 propagateContextChange位于ReactFiberNewContext.new.js中会区分懒传递还是饥饿传递。function propagateContextChangeT( workInProgress: Fiber, context: ReactContextT, renderLanes: Lanes, ): void { if (enableLazyContextPropagation) { // TODO: This path is only used by Cache components. Update // lazilyPropagateParentContextChanges to look for Cache components so they // can take advantage of lazy propagation. const forcePropagateEntireTree true; propagateContextChanges( workInProgress, [context], renderLanes, forcePropagateEntireTree, ); } else { propagateContextChange_eager(workInProgress, context, renderLanes); } }2.3 propagateContextChangesfunction propagateContextChangesT( workInProgress: Fiber, contexts: Arrayany, renderLanes: Lanes, forcePropagateEntireTree: boolean, ): void { // Only used by lazy implemenation if (!enableLazyContextPropagation) { return; } let fiber workInProgress.child; if (fiber ! null) { // Set the return pointer of the child to the work-in-progress fiber. fiber.return workInProgress; } while (fiber ! null) { let nextFiber; // Visit this fiber. const list fiber.dependencies; if (list ! null) { nextFiber fiber.child; let dep list.firstContext; findChangedDep: while (dep ! null) { // Assigning these to constants to help Flow const dependency dep; const consumer fiber; findContext: for (let i 0; i contexts.length; i) { const context: ReactContextT contexts[i]; // Check if the context matches. // TODO: Compare selected values to bail out early. if (dependency.context context) { consumer.lanes mergeLanes(consumer.lanes, renderLanes); const alternate consumer.alternate; if (alternate ! null) { alternate.lanes mergeLanes(alternate.lanes, renderLanes); } scheduleWorkOnParentPath(consumer.return, renderLanes); if (!forcePropagateEntireTree) { nextFiber null; } break findChangedDep; } } dep dependency.next; } } else if ( enableSuspenseServerRenderer fiber.tag DehydratedFragment ) { const parentSuspense fiber.return; parentSuspense.lanes mergeLanes(parentSuspense.lanes, renderLanes); const alternate parentSuspense.alternate; if (alternate ! null) { alternate.lanes mergeLanes(alternate.lanes, renderLanes); } scheduleWorkOnParentPath(parentSuspense, renderLanes); nextFiber null; } 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) { // Were 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; } }深度遍历所有的子代 fiber 然后找到里面具有 dependencies 的属性对比 dependencies 中的 context 和当前 Provider 的 context 是否是同一个调用scheduleWorkOnParentPath3、ContextConsumer从组件中得到上下文_context读取对应的value以组件的children作为render函数作渲染操作function updateContextConsumer( current: Fiber | null, workInProgress: Fiber, renderLanes: Lanes, ) { const consumerType: ReactConsumerTypeany workInProgress.type; const context: ReactContextany consumerType._context; const newProps workInProgress.pendingProps; const render newProps.children; if (__DEV__) { if (typeof render ! function) { console.error( A context consumer was rendered with multiple children, or a child that isnt a function. A context consumer expects a single child that is a function. If you did pass a function, make sure there is no trailing or leading whitespace around it., ); } } prepareToReadContext(workInProgress, renderLanes); const newValue readContext(context); if (enableSchedulingProfiler) { markComponentRenderStarted(workInProgress); } let newChildren; if (__DEV__) { newChildren callComponentInDEV(render, newValue, undefined); } else { newChildren render(newValue); } if (enableSchedulingProfiler) { markComponentRenderStopped(); } // React DevTools reads this flag. workInProgress.flags | PerformedWork; reconcileChildren(current, workInProgress, newChildren, renderLanes); return workInProgress.child; }