export function createContext<T>(
defaultValue: T,
calculateChangedBits: ?((a: T, b: T) => number)
): ReactContext<T> {
if (calculateChangedBits === undefined)
calculateChangedBits = null
const context: ReactContext<T> = {
$$typeof: REACT_CONTEXT_TYPE,
_calculateChangedBits: calculateChangedBits,
_currentValue: defaultValue,
_currentValue2: defaultValue,
_threadCount: 0,
Provider: null,
Consumer: null,
}
context.Provider = {
$$typeof: REACT_PROVIDER_TYPE,
_context: context,
}
context.Consumer = context
return context
}
function beginWork(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes
): Fiber | null {
const updateLanes = workInProgress.lanes
workInProgress.lanes = NoLanes
switch (workInProgress.tag) {
case ContextProvider:
return updateContextProvider(current, workInProgress, renderLanes)
case ContextConsumer:
return updateContextConsumer(current, workInProgress, renderLanes)
}
}
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, newValue)
if (oldProps !== null) {
const oldValue = oldProps.value
const changedBits = calculateChangedBits(context, newValue, oldValue)
if (changedBits === 0) {
if (
oldProps.children === newProps.children
&& !hasLegacyContextChanged()
) {
return bailoutOnAlreadyFinishedWork(
current,
workInProgress,
renderLanes
)
}
} else {
propagateContextChange(workInProgress, context, changedBits, renderLanes)
}
}
const newChildren = newProps.children
reconcileChildren(current, workInProgress, newChildren, renderLanes)
return workInProgress.child
}
function updateContextConsumer(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes
) {
const context: ReactContext<any> = workInProgress.type
const newProps = workInProgress.pendingProps
const render = newProps.children
prepareToReadContext(workInProgress, renderLanes)
const newValue = readContext(context, newProps.unstable_observedBits)
const newChildren = render(newValue)
reconcileChildren(current, workInProgress, newChildren, renderLanes)
return workInProgress.child
}
function prepareToReadContext(workInProgress: Fiber, renderLanes: Lanes): void {
currentlyRenderingFiber = workInProgress
lastContextDependency = null
lastContextWithAllBitsObserved = null
const dependencies = workInProgress.dependencies
if (dependencies !== null) {
const firstContext = dependencies.firstContext
if (firstContext !== null) {
if (includesSomeLane(dependencies.lanes, renderLanes)) {
markWorkInProgressReceivedUpdate()
}
dependencies.firstContext = null
}
}
}
function readContext<T>(
context: ReactContext<T>,
observedBits: void | number | boolean
): T {
const contextItem = {
context: context as ReactContext<mixed>,
observedBits: resolvedObservedBits,
next: null,
}
if (lastContextDependency === null) {
lastContextDependency = contextItem
currentlyRenderingFiber.dependencies = {
lanes: NoLanes,
firstContext: contextItem,
responders: null,
}
} else {
lastContextDependency = lastContextDependency.next = contextItem
}
return isPrimaryRenderer ? context._currentValue : context._currentValue2
}