第 03 章:启动与运行时拓扑
1. 从 App 到 HomeContainer
MobileNativeHomeRenderer 在 owner 或 native state 尚未就绪时返回 MobileNativeHomeLaunchSurface,而不是让原生引擎收到一份半完整 snapshot。这是一个首屏协议:空壳不是 error,而是等待 authoritative owner/state 的过渡状态。
2. 初始状态和增量状态是两条路径
HomeContainer.native.tsx 保留两份 JSON:
initialStateJsonRef:首次挂载时作为initialStateJsonprop 发送;lastSubmittedStateJsonRef:避免重复提交相同 state。
之后 useLayoutEffect 比较新的 stateJson,只在 JSON 变化时调用 nativeRef.current?.setState(stateJson)。
原生侧也明确区分:
| 阶段 | Android | iOS | 目的 |
|---|---|---|---|
| 首个状态 | submitInitialState 在 prop path 同步解析/应用 | submitInitialState 同步 decode,等待 bounds 后 apply | 首个 ViewRoot/布局周期就拥有完整 chrome |
| 后续状态 | 单线程 parser decode,再 post 到 UI | parsingQueue decode,再 dispatch main | 避免大 JSON 解码阻塞 UI |
| imperative update | setState → submitState | setState → 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:
- native engine 先重置 pager、scroll offset、refresh request、pending tab transition;
- React renderer 通过 owner token 重新生成 scope/session;
homeTabRenderState重新归属新 owner,必要时 imperative selectportfolio;- 旧的 slot 仍可能暂时存在,但 Surface 会把它视为未授权并 park/隐藏;
- 新 owner 的 snapshot 和 slot bundle 最终替换到位。
5. 运行时结论
启动链路的关键不是“尽快 render 一个组件”,而是控制三个时刻:
- 何时允许 native surface 出现;
- 何时把首状态视为可渲染;
- 何时允许用户事件回到 Store。
这三个时刻被分别编码在 splash readiness、state invariant 和 owner/revision checks 中。