0Pricing
React Academy · 课时

外部存储订阅的问题

了解撕裂现象,以及为什么在并发 React 中使用 useState 或 useRef 订阅外部存储并不安全。

外部存储订阅的问题 是 CoddyKit 上的免费 React Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 React Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 React Academy 课程共包含 4 节课。

什么是外部存储

外部存储是指存在于 React 树之外的任何状态来源,例如 Redux 存储、matchMedia 这样的浏览器接口,或带有自身订阅机制的普通模块级对象。

React 不拥有这些状态,因此必须订阅变更并读取快照,才能让组件与存储当前持有的内容保持同步。

朴素的 useState + useEffect 订阅

一种常见做法是将存储值读入 useState,然后使用 useEffect 进行订阅,并在存储变化时调用 setState。从表面看,这似乎能让组件保持最新。

这种方式适用于简单的同步渲染,但存在一个细微缺陷:当 React 并发渲染并在执行过程中暂停或重新开始工作时,这个缺陷就会显现出来。

撕裂问题

当界面的不同部分在同一次渲染过程中显示同一存储的不同值时,就会发生撕裂。并发渲染可能会中断并恢复工作,而存储可能在这期间发生变化。

结果是屏幕内容不一致:一个组件显示旧值,另一个组件显示新值。这种不一致在并发功能出现之前几乎不可能发生。

示例:渲染中途切换深色模式时的撕裂

假设许多组件在 React 并发渲染时读取主题存储。如果用户在渲染进行到一半时切换深色模式,那么切换前渲染的组件会显示浅色主题,切换后渲染的组件则会显示深色主题。

由于存储值在一次未被 React 视为原子操作的渲染过程中发生了变化,您会看到一帧一半浅色、一半深色的屏幕。

为什么 useEffect 为时已晚

副作用会在渲染提交后运行,因此基于 useEffect 的订阅无法保证渲染期间读取的值与提交时存储中的值一致。订阅触发得太晚,无法阻止不一致的绘制。

等到副作用重新订阅并更新状态时,不一致的画面可能已经展示给用户。

已弃用的 useMutableSource

一个名为 useMutableSource 的早期实验性接口曾尝试解决并发安全的外部读取问题,但事实证明它的接口很难正确使用,并且从未作为稳定接口发布。

React 团队用一个更简单、更易用的原语替代了它,在实现相同一致性保证的同时避免了那些容易出错的细节。

useSyncExternalStore 作为解决方案

useSyncExternalStore 是以并发安全方式订阅外部存储的官方钩子。它会与 React 协调,使读取结果在一次渲染过程中保持一致,组件也不会发生撕裂。

对于需要在并发渲染下可靠地将外部状态接入 React 的库作者来说,它已经成为推荐使用的原语。

哪些库受到影响

订阅外部存储的状态库会直接受到影响,包括 Redux、MobX 和 Valtio。并发功能发布后,为了继续保持安全,每个库都需要采用这个新的原语。

因此,它们的 React 绑定都进行了更新,在内部调用 useSyncExternalStore,而不再依赖旧的 useState 加 useEffect 模式。

一致的快照与并发安全

该钩子保证渲染期间读取存储库的每个组件都能看到相同的快照;如果存储库发生变化,而这种变化原本会导致数据撕裂,它还会强制同步重新渲染。

一致的快照与并发安全相结合,正是该钩子相比手写订阅所提供的核心价值。

面向未来的基础原语

通过使用 useSyncExternalStore,您的订阅会随着 React 渲染模型的发展继续保持正确。您可以采用框架提供的保证,而不是不完善地重新实现这些保证。

因此,它成为将任何外部真实数据源连接到 React 组件的持久且推荐的方式。

快速检查:数据撕裂问题

确认并发渲染中数据撕裂的含义。

回顾:外部存储订阅问题

外部存储位于 React 之外,而朴素的 useState 加 useEffect 订阅在渲染变为并发模式后无法阻止数据撕裂。副作用执行得太晚,无法保证一次渲染中的读取保持一致。

useSyncExternalStore 取代了已被放弃的 useMutableSource,并提供一致的快照与并发安全。Redux、MobX 和 Valtio 等库都采用了它,将其作为面向未来的存储库订阅基础原语。

常见问题解答

「外部存储订阅的问题」课时是免费的吗?

是的 — 「外部存储订阅的问题」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 React Academy 课程的其余内容,请升级到 CoddyKit PRO。 React Academy 课程共包含 4 节课。

「外部存储订阅的问题」这节课中我会学到什么?

了解撕裂现象,以及为什么在并发 React 中使用 useState 或 useRef 订阅外部存储并不安全。 你通过在浏览器中直接运行的动手代码来练习 React Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 React Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 React Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「外部存储订阅的问题」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 React Academy 课中编写并运行代码吗?

能。每节 React Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 外部存储订阅的问题
  2. useSyncExternalStore API 与参数
  3. 订阅浏览器 API
  4. 使用 useSyncExternalStore 构建自定义存储
← 返回 React Academy