☰
Recoil Sync 0.2.0 变更详解:updateItems、URL 参数重置与 handlers 稳定性警告
2026/10/1 7:40:34 网站建设 项目流程
  • 前端

【免费下载链接】Recoil

Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone, while being compatible with the newest features of React.

项目地址:https://gitcode.com/gh_mirrors/re/Recoil
点击查看免费下载

本文以recoil-sync的官方变更日志(CHANGELOG-recoil-sync.md)为主体骨架,结合本仓库packages/recoil-sync/下的源码与测试用例,逐条拆解 0.2.0 版本的三个关键变更:listen回调新增updateItems()导出、queryParams模式下移除参数时原子重置行为,以及<RecoilURLSyncTransit>的handlers稳定性开发期警告。读完本文,你将能准确理解这些 API 变化的底层实现、适配旧代码所需的迁移要点,以及如何通过仓库内测试用例验证新行为。

一、版本脉络:从 0.1.0 到 0.2.0

recoil-sync是 Recoil 官方的状态同步附加库,用于将 Recoil 状态与浏览器 URL 等外部系统双向同步。其核心用法是在目标 atom 上挂载syncEffect(),然后在<RecoilRoot>内放置<RecoilSync/>来声明“如何同步”。

从 CHANGELOG-recoil-sync.md 可以看到清晰的版本演进:

版本日期主要内容
0.1.02022-06-21首次开源发布
0.1.12022-08-18升级依赖的@recoiljs/refine到 0.1.1(含修复)
0.2.02022-10-06导出updateItems();URL 参数移除触发原子重置;新增handlers稳定性警告
UPCOMING未发布将弃用的substr()迁移到substring()以提升浏览器兼容性(PR #2089)

其中 0.2.0 是当前仓库中功能变更最集中的版本,也是本文的核心讲解对象。三条变更分别对应RecoilSync.js、RecoilSync_URL.js和RecoilSync_URLTransit.js三个模块,下面逐一深入。

二、变更一:listen回调新增updateItems()导出

2.1 变更内容

0.2.0 之前,<RecoilSync>的listenprop 回调只提供两个更新函数(对应 PR #2017、#2035):

  • updateItem(itemKey, newValue):更新单个 item;
  • updateAllKnownItems(itemSnapshot):用完整的 item 快照更新所有已知 item。

0.2.0 起新增了第三个导出updateItems(itemSnapshot),语义介于两者之间:它接收一个ItemSnapshot(Map<ItemKey, DefaultValue | mixed>),只更新该快照中明确指定的 item,不会像updateAllKnownItems那样把“未出现在快照中的已注册 item”一并重置为默认值。

2.2 源码印证

在 RecoilSync.js 中可以看到三个导出的类型定义:

export type UpdateItem = <T>(ItemKey, DefaultValue | T) => void; export type UpdateItems = ItemSnapshot => void; export type UpdateAllKnownItems = ItemSnapshot => void; export type ListenInterface = { updateItem: UpdateItem, updateItems: UpdateItems, updateAllKnownItems: UpdateAllKnownItems, };

三个函数在useRecoilSync()内部通过useCallback与useRecoilTransaction_UNSTABLE组装:

  • updateItem只是把单个键值对包装成Map后转调updateItems(RecoilSync.js);
  • updateAllKnownItems在调用updateItems之前,会遍历当前storeKey下注册的所有 atom effect,把快照中缺失的subscribedItemKeys补成DefaultValue再一并提交(RecoilSync.js)。
const updateAllKnownItems = useCallback( (itemSnapshot: ItemSnapshot) => { // Reset the value of any items that are registered and not included in // the user-provided snapshot. const atomRegistry = registries.getAtomRegistry(recoilStoreID, storeKey); for (const [, registration] of atomRegistry) { for (const [, {subscribedItemKeys}] of registration.effects) { for (const itemKey of subscribedItemKeys) { if (!itemSnapshot.has(itemKey)) { itemSnapshot.set(itemKey, DEFAULT_VALUE); } } } } updateItems(itemSnapshot); }, [recoilStoreID, storeKey, updateItems], );

正是这个“补默认值”的前置循环,构成了updateItems与updateAllKnownItems的本质差异:前者只动你给的数据,后者会把注册表里没给到的 item 全部重置。

2.3 使用建议与迁移要点

  • 当外部系统推来完整状态快照(例如整份 URL 解析结果)时,仍用updateAllKnownItems,它能保证与存储状态严格一致;
  • 当外部系统只推来增量变更、且不希望波及未涉及的 atom 时,用新的updateItems更安全;
  • 若你曾用updateAllKnownItems模拟增量更新,升级到 0.2.0 后可改用updateItems获得更精确的控制。

三、变更二:queryParams移除参数会重置原子

3.1 变更内容

0.2.0 起,当使用location={{part: 'queryParams', param: 'foo'}}这类带param的配置、且该参数从 URL 中被移除时,对应原子会被重置(PR #1900、#1976)。变更日志同时指出:当一个 atom 可能同时与多个 URL 参数同步时,这是一个轻微的不兼容变更——因为过去原子在参数缺失时可能保持旧值,现在则会回落为默认值。

3.2 源码印证

解析逻辑位于 RecoilSync_URL.js 的parseURL():

case 'queryParams': { const searchParams = new URLSearchParams(url.search); const {param} = loc; if (param != null) { const stateStr = searchParams.get(param); return stateStr != null ? wrapState(deserialize(stateStr)) : new Map(); } ... }

关键点在于:参数存在时返回wrapState(deserialize(stateStr))快照;参数不存在时返回空的new Map()。空 Map 经updateAllKnownItems通道进入原子更新后,订阅了该itemKey的 atom 因快照中找不到对应键,就会被补成DefaultValue并重置——这正是“移除参数即重置”的机制来源。

同时,编码侧 encodeURL 也做了对称处理:当值为DefaultValue时调用searchParams.delete(itemKey),从 URL 中删除该参数,而不是写入一个空值。

3.3 测试用例佐证

RecoilSync_URLListen-test.js 明确覆盖了这一行为:当gotoURL把locFoo(queryParams + param: 'foo')下的所有键移除后,三个 atom 全部回落为DEFAULT:

// Subscribe to reset await act(() => gotoURL([ [locFoo, {'recoil-url-sync listen to multiple storage': 'C'}], [locBar, {}], ]), ); expect(container.textContent).toBe('"DEFAULT""DEFAULT""DEFAULT"');

这个测试同时也展示了“多个 URL 参数同步到多个存储”时,移除一个存储的参数不会影响另一个存储的原子状态——但同一存储下若参数被删,则订阅它的 atom 一律重置。

3.4 迁移注意

如果你的业务依赖“参数消失时原子保持上一次值”的旧行为,0.2.0 之后需要在listen/read层面自行兜底,例如在deserialize或read回调中为缺失参数返回可接受的默认值,而不是依赖原子内建的保持行为。

四、变更三:<RecoilURLSyncTransit>的handlers稳定性警告

4.1 变更内容

0.2.0 增加了开发期警告(PR #2044):如果检测到<RecoilURLSyncTransit>的handlersprop 引用在渲染之间发生变化(不稳定),会通过expectationViolation输出警告。handlers用于扩展 Transit 序列化格式,支持Date、Set、Map等自定义类型的编解码。

4.2 源码印证

RecoilSync_URLTransit.js 用usePrevious对比前后两次的handlersProp:

const previousHandlers = usePrevious(handlersProp); useEffect(() => { if (__DEV__) { if (previousHandlers != null && previousHandlers !== handlersProp) { const message = `<RecoilURLSyncTransit> 'handlers' prop was detected to be unstable. It is important that this is a stable or memoized array instance. Otherwise you may miss URL changes as the listener is re-subscribed. `; expectationViolation(message); } } }, [previousHandlers, handlersProp]);

警告的核心危害是:handlers变化会重新触发useMemo重建 writer/reader,进而让serialize/deserialize引用变化,最终导致listen监听器重新订阅,从而可能错过 URL 变更事件。

4.3 正确写法

handlers应在组件顶层用模块常量、useMemo或useCallback稳定化:

const MY_HANDLERS = []; // 或使用 useMemo(() => [...], []) function MyApp() { return ( <RecoilRoot> <RecoilURLSyncTransit location={{part: 'hash'}} handlers={MY_HANDLERS} > ... </RecoilURLSyncTransit> </RecoilRoot> ); }

不要直接在 JSX 内联handlers={[...]},否则每次渲染都会产生新数组引用并触发警告。

五、附:transit-js内置处理器与 URL 编码器选择

RecoilURLSyncTransit自带 4 个内置 handler(RecoilSync_URLTransit.js):

tag类型编码策略
DateDatetoISOString()字符串
SetSet数组
MapMap键值对数组
__DVDefaultValue编码为0(最短 URL 编码)

注意RecoilURLSyncTransit与RecoilURLSyncJSON一样不支持location.part === 'href',传入即抛错(RecoilSync_URLJSON.js与RecoilSync_URLTransit.js均显式检查)。若采用 JSON 编码,请使用 RecoilSync_URLJSON.js 提供的RecoilURLSyncJSON。

六、0.2.0 升级清单(快速自查)

针对上述三个变更,升级到 0.2.0 时建议依次确认:

  1. 若自定义 store 的listen回调需要增量更新语义,可改用新增的updateItems;
  2. 检查所有queryParams + param场景,确认参数被删除时原子重置为默认值是否符合预期;
  3. 检查<RecoilURLSyncTransit>的handlers是否由稳定的数组实例提供;
  4. 关注 UPCOMING 中的substr()→substring()迁移(CHANGELOG-recoil-sync.md),该改动面向不支持substr的旧浏览器环境,不影响公共 API。

如需进一步动手验证,可在仓库中运行recoil-sync相关测试(如RecoilSync_URLListen-test.js、RecoilSync_URLPush-test.js),它们完整覆盖了“监听 URL 变化”“push/replace 历史记录”等核心行为,可作为理解 API 语义的第一手实验材料。

  • 前端

【免费下载链接】Recoil

Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone, while being compatible with the newest features of React.

项目地址:https://gitcode.com/gh_mirrors/re/Recoil
点击查看免费下载

相关推荐

上一篇:Mac Mouse Fix 快速指南:第三方鼠标安装、按键自定义、滚轮设置 15 分钟搞定
下一篇:Animagine XL 3.1深度技术解析:高性能动漫AI绘画模型实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询