Skip to content

第 03 章:启动与运行时拓扑 ​

1. 从 App 到 HomeContainer ​

MobileNativeHomeRenderer 在 owner 或 native state 尚未就绪时返回 MobileNativeHomeLaunchSurface,而不是让原生引擎收到一份半完整 snapshot。这是一个首屏协议:空壳不是 error,而是等待 authoritative owner/state 的过渡状态。

2. 初始状态和增量状态是两条路径 ​

HomeContainer.native.tsx 保留两份 JSON:

  • initialStateJsonRef:首次挂载时作为 initialStateJson prop 发送;
  • lastSubmittedStateJsonRef:避免重复提交相同 state。

之后 useLayoutEffect 比较新的 stateJson,只在 JSON 变化时调用 nativeRef.current?.setState(stateJson)。

原生侧也明确区分:

阶段AndroidiOS目的
首个状态submitInitialState 在 prop path 同步解析/应用submitInitialState 同步 decode,等待 bounds 后 apply首个 ViewRoot/布局周期就拥有完整 chrome
后续状态单线程 parser decode,再 post 到 UIparsingQueue decode,再 dispatch main避免大 JSON 解码阻塞 UI
imperative updatesetState → submitStatesetState → submitState与 React prop path 共享状态验证

3. splash 和 native surface 的关系 ​

packages/kit/src/provider/SplashProvider.tsx 有专门的 nativeHomeSurfaceReady 判断:当 native Home 被 feature flag 打开时,splash 不能只看通用 hydration,还要看 launch snapshot 是否足以构建首屏 surface。这样能避免 splash 消失后看到一个“React 已加载、Home 原生壳还没准备好”的闪烁。

完整冷启动还会在 homeDisplaySnapshotStartup.ts 中等待 globalColdStartHydrationReadyHandler.ready,读取当前 owner 的预备 display snapshot,并记录 Home:displayCache:startupLoadStart/Done 性能标记。

4. owner 变化时的拓扑重置 ​

当 state.owner 从 A 变成 B:

  1. native engine 先重置 pager、scroll offset、refresh request、pending tab transition;
  2. React renderer 通过 owner token 重新生成 scope/session;
  3. homeTabRenderState 重新归属新 owner,必要时 imperative select portfolio;
  4. 旧的 slot 仍可能暂时存在,但 Surface 会把它视为未授权并 park/隐藏;
  5. 新 owner 的 snapshot 和 slot bundle 最终替换到位。

5. 运行时结论 ​

启动链路的关键不是“尽快 render 一个组件”,而是控制三个时刻:

  • 何时允许 native surface 出现;
  • 何时把首状态视为可渲染;
  • 何时允许用户事件回到 Store。

这三个时刻被分别编码在 splash readiness、state invariant 和 owner/revision checks 中。

基于 app-monorepo 2026-07-31 源码快照整理 · 非官方文档