用途:当组件或 hook 使用 useObservable、useSyncObservable 或 useObservablePromise,或怀疑存在重渲染、加载闪烁、重复订阅时使用。
背景:react-rx 每个 observable 标识对应一个共享 store,新标识即新 store 并重新订阅。react-rx 7 无 warm-up,标识变化会先渲染 initialValue 再重新订阅,表现为加载闪烁;initialValue 为必填,缺失会在渲染时抛错。useObservableSubject 取代 useObservableEvent。react-rx 6 会在渲染期间订阅一次替代 observable,因此 6 上正常的代码在 7 上可能闪烁。
查找方式:在仓库根目录用 rg 搜索调用点(如 rg -n "use(Sync)?Observable(Promise)?(" packages/sanity/src packages/@sanity/vision/src -g '!**/.test.'),用 -U 搜缺少 initialValue 的调用,用多行正则提取 useMemo 依赖数组。判断标准:依赖在编辑时变化(文档值、渲染中构造的数组或对象、内联 []/{}、重建的 context 值)、of(...) 或 .pipe(...) 在渲染中内联构造、依赖列表是管道的超集、缺少稳定 initialValue、use() 与 useObservablePromise 位于同一组件。
运行时核对:用 agent-react-devtools 统计重渲染,用临时 console.log 统计订阅数,并用 Playwright 驱动交互前后对比计数。注意重渲染计数看不到相同值的重新订阅,隐藏 Activity 树不显示为重渲染。
重构:先区分标识输入与流式输入;将流式输入放入一个 useMemo 的输入记录,用 BehaviorSubject 经 useEffect 推送,标识输入变化时替换 subject;在依赖仅含标识输入、subject 和 store 函数的 useMemo 中构建 observable,经 distinctUntilChanged、switchMap、再 distinctUntilChanged 输出比较器。常量 observable 提升到模块作用域。消费者需同步首帧时用 useSyncObservable,否则用 useObservable。接受的代价是输出变化的改动多一次渲染。无值形输入或需每次同步更新时不适用,也不要用已弃用的 useUnique 稳定输入。
测试:按 useValuePreview.test.tsx 的 Harness 模式断言字面帧与订阅计数,覆盖同目标编辑两次、每次渲染重建的相等输入、标识变化三种场景。
限制:本技能步骤针对该仓库与 react-rx 版本,其他环境信息暂未提供;不得就地覆盖 pnpm 存储的硬链接 dist 文件。