React Fiber 范围
一、作用
二、创建作用域实例
export function createScopeInstance(): ReactScopeInstance {
return {
DO_NOT_USE_queryAllNodes,
DO_NOT_USE_queryFirstNode,
containsNode,
getChildContextValues,
};
}
三、常量
// 空对象
const emptyObject = {};
四、工具
1. 获取挂起回退子组件
function getSuspenseFallbackChild(fiber: Fiber): Fiber | null {
return ((fiber.child as any as Fiber).sibling as any as Fiber).child;
}
2. 收集作用域节点
备注
getPublicInstance()由 宿主环境提供isFiberSuspenseAndTimedOut()由 ReactFiberTreeReflection#isFiberSuspenseAndTimedOut 实现
function collectScopedNodes(
node: Fiber,
fn: ReactScopeQuery,
scopedNodes: Array<any>,
): void {
if (enableScopeAPI) {
if (node.tag === HostComponent) {
const { type, memoizedProps, stateNode } = node;
const instance = getPublicInstance(stateNode);
if (
instance !== null &&
fn(type, memoizedProps || emptyObject, instance) === true
) {
scopedNodes.push(instance);
}
}
let child = node.child;
if (isFiberSuspenseAndTimedOut(node)) {
child = getSuspenseFallbackChild(node);
}
if (child !== null) {
collectScopedNodesFromChildren(child, fn, scopedNodes);
}
}
}
3. 收集第一个作用域节点
备注
getPublicInstance()由 宿主环境提供isFiberSuspenseAndTimedOut()由 ReactFiberTreeReflection#isFiberSuspenseAndTimedOut 实现
function collectFirstScopedNode(
node: Fiber,
fn: ReactScopeQuery,
): null | Object {
if (enableScopeAPI) {
if (node.tag === HostComponent) {
const { type, memoizedProps, stateNode } = node;
const instance = getPublicInstance(stateNode);
if (instance !== null && fn(type, memoizedProps, instance) === true) {
return instance;
}
}
let child = node.child;
if (isFiberSuspenseAndTimedOut(node)) {
child = getSuspenseFallbackChild(node);
}
if (child !== null) {
return collectFirstScopedNodeFromChildren(child, fn);
}
}
return null;
}
4. 从子节点收集作用域节点
function collectScopedNodesFromChildren(
startingChild: Fiber,
fn: ReactScopeQuery,
scopedNodes: Array<any>,
): void {
let child: null | Fiber = startingChild;
while (child !== null) {
collectScopedNodes(child, fn, scopedNodes);
child = child.sibling;
}
}
5. 从子节点收集第一个作用域节点
function collectFirstScopedNodeFromChildren(
startingChild: Fiber,
fn: ReactScopeQuery,
): Object | null {
let child: null | Fiber = startingChild;
while (child !== null) {
const scopedNode = collectFirstScopedNode(child, fn);
if (scopedNode !== null) {
return scopedNode;
}
child = child.sibling;
}
return null;
}
6. 收集最近的上下文值
备注
isFiberSuspenseAndTimedOut()由 ReactFiberTreeReflection#isFiberSuspenseAndTimedOut 实现
function collectNearestContextValues<T>(
node: Fiber,
context: ReactContext<T>,
childContextValues: Array<T>,
): void {
if (node.tag === ContextProvider && node.type === context) {
const contextValue = node.memoizedProps.value;
childContextValues.push(contextValue);
} else {
let child = node.child;
if (isFiberSuspenseAndTimedOut(node)) {
child = getSuspenseFallbackChild(node);
}
if (child !== null) {
collectNearestChildContextValues(child, context, childContextValues);
}
}
}
7. 收集最近的子上下文值
function collectNearestChildContextValues<T>(
startingChild: Fiber | null,
context: ReactContext<T>,
childContextValues: Array<T>,
): void {
let child = startingChild;
while (child !== null) {
collectNearestContextValues(child, context, childContextValues);
child = child.sibling;
}
}
8. 查询所有节点(不要使用)
备注
getInstanceFromScope()由 宿主环境提供
function DO_NOT_USE_queryAllNodes(
this: $FlowFixMe,
fn: ReactScopeQuery,
): null | Array<Object> {
const currentFiber = getInstanceFromScope(this);
if (currentFiber === null) {
return null;
}
const child = currentFiber.child;
const scopedNodes: Array<any> = [];
if (child !== null) {
collectScopedNodesFromChildren(child, fn, scopedNodes);
}
return scopedNodes.length === 0 ? null : scopedNodes;
}
9. 查询第一个节点(不要使用)
备注
getInstanceFromScope()由 宿主环境提供
function DO_NOT_USE_queryFirstNode(
this: $FlowFixMe,
fn: ReactScopeQuery,
): null | Object {
const currentFiber = getInstanceFromScope(this);
if (currentFiber === null) {
return null;
}
const child = currentFiber.child;
if (child !== null) {
return collectFirstScopedNodeFromChildren(child, fn);
}
return null;
}
10. 判断是否包含节点
备注
getInstanceFromNode()由 宿主环境提供
function containsNode(this: $FlowFixMe, node: Object): boolean {
let fiber = getInstanceFromNode(node);
while (fiber !== null) {
if (fiber.tag === ScopeComponent && fiber.stateNode === this) {
return true;
}
fiber = fiber.return;
}
return false;
}
11. 获取子上下文值
备注
getInstanceFromScope()由 宿主环境提供
function getChildContextValues<T>(
this: $FlowFixMe,
context: ReactContext<T>,
): Array<T> {
const currentFiber = getInstanceFromScope(this);
if (currentFiber === null) {
return [];
}
const child = currentFiber.child;
const childContextValues: Array<T> = [];
if (child !== null) {
collectNearestChildContextValues(child, context, childContextValues);
}
return childContextValues;
}