1、createContext
创建ReactContext对象。
function createContext<T>(defaultValue: T): ReactContext<T> {
const context: ReactContext<T> = {
$$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 ReactContext<T> = {
$$typeof: Symbol | number,
Consumer: ReactContext<T>,
Provider: ReactProviderType<T>,
_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_TYPE
- Consumer是element对象$$typeof: REACT_CONTEXT_TYPE
-
_currentValue保存传递给 Provider 的value
2、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、updateContextProvider
function updateContextProvider(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
) {
const providerType: ReactProviderType<any> = workInProgress.type;
const context: ReactContext<any> = 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(在主渲染情况下)或者_currentValue2
- context的value有变动时,调用
propagateContextChange
进行更新 - 调度子节点更新reconcileChildren
2.2 propagateContextChange
位于ReactFiberNewContext.new.js中,会区分懒传递还是饥饿传递。
function propagateContextChange<T>(
workInProgress: Fiber,
context: ReactContext<T>,
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 propagateContextChanges
function propagateContextChanges<T>(
workInProgress: Fiber,
contexts: Array<any>,
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: ReactContext<T> = 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) {
// 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;
}
}
- 深度遍历所有的子代 fiber ,然后找到里面具有 dependencies 的属性
- 对比 dependencies 中的 context 和当前 Provider 的 context 是否是同一个,调用scheduleWorkOnParentPath