Jotai 项目中 React 19 与 atomWithObservable 的 Suspense 问题解析
问题背景
在 React 状态管理库 Jotai 的最新使用中,开发者发现当升级到 React 19 后,useAtomValue 与 atomWithObservable 的组合使用会出现一个意外的行为:每当 observable 产生新值时,组件会重新触发 Suspense 状态。这显然不是预期的行为,因为 Suspense 应该只在初始加载时触发,而不应在数据更新时重复触发。
技术细节分析
Jotai 的核心概念
Jotai 是一个基于原子(atom)概念的 React 状态管理库。atomWithObservable 是一个特殊的原子创建函数,它允许将 RxJS 或其他兼容的 observable 转换为 Jotai 原子。useAtomValue 则是用于在 React 组件中订阅原子值的 hook。
React 19 的变化
React 19 引入了一些内部机制的变化,特别是在并发渲染和 Suspense 处理方面。这些变化影响了 Jotai 中 observable 原子的行为模式。具体来说,React 19 对异步值的处理更加严格,导致 observable 发出的每个新值都被视为可能需要重新 Suspense 的场景。
问题表现
当使用以下代码模式时:
const observableAtom = atomWithObservable(() => someObservable);
const value = useAtomValue(observableAtom);
在 React 19 环境下,每当 observable 发出新值时,组件会重新进入 Suspense 状态,导致不必要的加载状态闪烁和性能开销。
临时解决方案
目前发现的有效临时解决方案是给 useAtomValue 添加一个 delay: 0 的配置:
const value = useAtomValue(observableAtom, { delay: 0 });
这个配置通过将值的更新推迟到下一个 macrotask(通过 setTimeout(fn, 0) 实现),绕过了 React 19 的立即 Suspense 行为。
技术原理探究
为什么 delay: 0 有效
设置 delay: 0 实际上是将状态更新从同步改为异步。React 19 的并发渲染器对同步更新和异步更新有不同的处理策略。对于异步更新,React 会采用更宽松的 Suspense 策略,不会为每个新值触发 Suspense。
更深层的机制
这可能与 React 19 对"过渡"(transition)概念的强化有关。React 19 可能将 observable 的每次更新都视为潜在的"关键"更新,从而触发 Suspense。而通过 delay: 0 将其转为异步更新后,React 会将其视为"非关键"更新,从而避免不必要的 Suspense。
长期解决方案展望
虽然 delay: 0 是一个有效的临时解决方案,但长期来看,Jotai 可能需要针对 React 19 进行专门的适配:
- 修改
atomWithObservable的内部实现,使其与 React 19 的并发特性更好地兼容 - 提供专门的 React 19 适配层,自动处理这类边界情况
- 与 React 团队协作,明确 observable 集成的最佳实践
最佳实践建议
对于正在使用或计划使用 Jotai 与 React 19 的开发者:
- 如果遇到 Suspense 相关问题,首先尝试
delay: 0解决方案 - 密切关注 Jotai 的更新日志,特别是关于 React 19 兼容性的说明
- 考虑在 observable 原子外添加一层缓存或防抖,减少不必要的更新
- 对于关键路径,进行充分的测试以确保更新行为符合预期
总结
React 19 的架构变化为状态管理库带来了新的挑战和机遇。Jotai 作为基于原子的轻量级状态管理方案,正在积极适应这些变化。当前 useAtomValue 与 atomWithObservable 的 Suspense 问题虽然可以通过简单的方式解决,但也提醒我们在升级 React 版本时需要全面测试状态管理相关的行为。随着 React 19 的逐步普及,相信 Jotai 团队会提供更加完善的解决方案。
AutoGLM-Phone-9BAutoGLM-Phone-9B是基于AutoGLM构建的移动智能助手框架,依托多模态感知理解手机屏幕并执行自动化操作。Jinja00
Kimi-K2-ThinkingKimi K2 Thinking 是最新、性能最强的开源思维模型。从 Kimi K2 开始,我们将其打造为能够逐步推理并动态调用工具的思维智能体。通过显著提升多步推理深度,并在 200–300 次连续调用中保持稳定的工具使用能力,它在 Humanity's Last Exam (HLE)、BrowseComp 等基准测试中树立了新的技术标杆。同时,K2 Thinking 是原生 INT4 量化模型,具备 256k 上下文窗口,实现了推理延迟和 GPU 内存占用的无损降低。Python00
GLM-4.6V-FP8GLM-4.6V-FP8是GLM-V系列开源模型,支持128K上下文窗口,融合原生多模态函数调用能力,实现从视觉感知到执行的闭环。具备文档理解、图文生成、前端重构等功能,适用于云集群与本地部署,在同类参数规模中视觉理解性能领先。Jinja00
HunyuanOCRHunyuanOCR 是基于混元原生多模态架构打造的领先端到端 OCR 专家级视觉语言模型。它采用仅 10 亿参数的轻量化设计,在业界多项基准测试中取得了当前最佳性能。该模型不仅精通复杂多语言文档解析,还在文本检测与识别、开放域信息抽取、视频字幕提取及图片翻译等实际应用场景中表现卓越。00
GLM-ASR-Nano-2512GLM-ASR-Nano-2512 是一款稳健的开源语音识别模型,参数规模为 15 亿。该模型专为应对真实场景的复杂性而设计,在保持紧凑体量的同时,多项基准测试表现优于 OpenAI Whisper V3。Python00
GLM-TTSGLM-TTS 是一款基于大语言模型的高质量文本转语音(TTS)合成系统,支持零样本语音克隆和流式推理。该系统采用两阶段架构,结合了用于语音 token 生成的大语言模型(LLM)和用于波形合成的流匹配(Flow Matching)模型。 通过引入多奖励强化学习框架,GLM-TTS 显著提升了合成语音的表现力,相比传统 TTS 系统实现了更自然的情感控制。Python00
Spark-Formalizer-X1-7BSpark-Formalizer 是由科大讯飞团队开发的专用大型语言模型,专注于数学自动形式化任务。该模型擅长将自然语言数学问题转化为精确的 Lean4 形式化语句,在形式化语句生成方面达到了业界领先水平。Python00