Context
context 对象
- 通过
createContext创建
- 本质:
REACT_CONTEXT_TYPE 类型的react元素
_currentValue: 用来传递值(value)
const context: ReactContext<T> = {
$$typeof: REACT_CONTEXT_TYPE,
_calculateChangedBits: calculateChangedBits,
_currentValue: defaultValue,
_currentValue2: defaultValue,
_threadCount: 0,
Provider: (null: any),
Consumer: (null: any),
};
readContext
- 建立当前
fiber.dependencies 和 context对象的关联
fiber.dependencies 已链表的形式存储着 createItem .
const contextItem = {
context: ((context: any): 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;
```
#### Provider
- 本质: `REACT_PROVIDER_TYPE类型的react元素`
1. `_context`: 保存则对当前 `context对象的引用`
```js
context.Provider = {
$$typeof: REACT_PROVIDER_TYPE,
_context: context,
};
updateContextProvider : 调和 Provider
pushProvider : 重新设置 context._currentValue为 <Provider value/> 这也是 Provider传递值的方式即通过 currentValue传递
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;
}
calculateChangedBits: 对比 newValue 和 oldValue看是否发生了更新,如果没有则返回 0.
bailoutOnAlreadyFinishedWork: 没有更新则命中 bailoutOnAlreadyFinishedWork 直接 cloneChild继续调和子树.
propagateContextChange: 否则进入更新逻辑
propagateContextChange: 提高所有使用了当前context的fiber的lanes
- 遍历子fiber , 通过
fiber.dependencies 找到所有使用context的子fiber, 并将其父链路上的所有fiber的lanes优先级提高(scheduleWorkOnParentPath).在后续调和过程中确保其继续调和.
- 这里就是 context 说性能不高的原因吗?因为在寻找使用了 context对象的 fiber时,需要遍历整棵子树
export function propagateContextChange(
workInProgress: Fiber,
context: ReactContext<mixed>,
changedBits: number,
renderLanes: Lanes,
): void {
let fiber = workInProgress.child;
if (fiber !== null) {
fiber.return = workInProgress;
}
while (fiber !== null) {
let nextFiber;
const list = fiber.dependencies;
console.log('list', list);
if (list !== null) {
nextFiber = fiber.child;
let dependency = list.firstContext;
while (dependency !== null) {
if (
dependency.context === context &&
(dependency.observedBits & changedBits) !== 0
) {
if (fiber.tag === ClassComponent) {
const update = createUpdate(
NoTimestamp,
pickArbitraryLane(renderLanes),
);
update.tag = ForceUpdate;
enqueueUpdate(fiber, update);
}
fiber.lanes = mergeLanes(fiber.lanes, renderLanes);
const alternate = fiber.alternate;
if (alternate !== null) {
alternate.lanes = mergeLanes(alternate.lanes, renderLanes);
}
scheduleWorkOnParentPath(fiber.return, renderLanes);
list.lanes = mergeLanes(list.lanes, renderLanes);
break;
}
dependency = dependency.next;
}
}
if (nextFiber !== null) {
nextFiber.return = fiber;
} else {
nextFiber = fiber;
while (nextFiber !== null) {
if (nextFiber === workInProgress) {
nextFiber = null;
break;
}
const sibling = nextFiber.sibling;
if (sibling !== null) {
sibling.return = nextFiber.return;
nextFiber = sibling;
break;
}
nextFiber = nextFiber.return;
}
}
fiber = nextFiber;
Consumer
context.Consumer = context;
useContext
contextItem.context 就是 useContext 传递过来的context对象
Consumer 的 render props
contextItem.context 是通过 fiber.type 进行获取的,Consumer的type 就是 [[#context 对象]]
- 具体实现见
updateContextConsumer
function updateContextConsumer(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
) {
let context: ReactContext<any> = workInProgress.type;
const newProps = workInProgress.pendingProps;
const render = newProps.children;
prepareToReadContext(workInProgress, renderLanes);
const newValue = readContext(context, newProps.unstable_observedBits);
let newChildren;
newChildren = render(newValue);
workInProgress.flags |= PerformedWork;
reconcileChildren(current, workInProgress, newChildren, renderLanes);
return workInProgress.child;
}
contextType
- 在[[#updateContextProvider]] 中 , 如果类组件使用context时,则创建一个高优先级的
ForceUpdate update对象