Skip to content

Offscreen

这是一个基本不怎么使用的组件,但是在 React 内部很多组价都是基于其处理子节点的显示状态的。

创建

在 React 暴露的方法中,并没有找到 Offscreen 组件的定义。 其只是暴露了一个 unstable_Offscreen => export const REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen'); 用于我们判断子节点的类型是否是 Offscreen 组件。 所以我们无法通过 <React.Offscreen /> 去创建一个 Offscreen 组件。也不能通过 React.createElement(REACT_OFFSCREEN_TYPE) 去创建一个 Offscreen 组件。

其中有两个关键的入参 :

  • mode : 控制子节点的显示状态

但是我们还是需要关注一下这个组件的对象。

组件对象

其创建函数为 createFiberFromOffscreen(offscreenProps, mode, NoLanes, null);

js
export function createFiberFromOffscreen(
  pendingProps: OffscreenProps,
  mode: TypeOfMode,
  lanes: Lanes,
  key: null | string
) {
  const fiber = createFiber(OffscreenComponent, pendingProps, key, mode);
  fiber.elementType = REACT_OFFSCREEN_TYPE;
  fiber.lanes = lanes;
  const primaryChildInstance: OffscreenInstance = {
    isHidden: false,
  };
  fiber.stateNode = primaryChildInstance;
  return fiber;
}

const primaryChildProps: OffscreenProps = {
  mode: "visible",
  children: primaryChildren,
};

Fiber 结构

js
const OffscreenFiber = {
  tag: OffscreenComponent, // 22
  key: key,
  elementType: Symbol.for("react.offscreen"),
  type: null,
  stateNode: { isHidden: false | true },
  pendingProps: pendingProps, // { mode : 'hide' | 'visible' , children : ReactNode }
  alternate: null,

  // 在 Hide 状态下 才会存在这些参数,在 visible 状态下 不存在
  memoizedState: {
    baseLanes: renderLanes,
    cachePool: getSuspendedCache(),
    transitions: null,
  },
};

beginWork 阶段

  1. 因为 Offscreen 组件 lane 优先级是比较低的,所以在 beginWork 阶段,其子节点的渲染优先级也会被跳过,从而导致子节点中高优先级的 lane 不会被执行。为了解决这个问题,React 内部会在 beginWork 阶段,对 Offscreen 组件每次渲染时,如果 renderLanes 中不包含 OffscreenLane 的时候,会将执行的 lane 缓存到 OffscreenLane.stateNode.baseLane 中,等到处理 OffscreenLane的时候一起处理。

  2. Offscreen 组件在 mode : 'hide' 的时候其子节点会执行渲染么?

在 Render 阶段, 其不管是 visible 还是 hide 都会执行。 在 Commit 阶段,只有