☰
react-native-mmkv 集成 React Query:用 createAsyncStoragePersister 将查询缓存持久化到 MMKV
2026/9/25 4:56:20 网站建设 项目流程

【免费下载链接】react-native-mmkv

⚡️ The fastest key/value storage for React Native. ~30x faster than AsyncStorage!

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

react-query(TanStack Query)默认把请求缓存保存在内存中,应用重启后缓存即失效。本文讲解如何在 React Native 项目中,把 react-query 的持久化层从 AsyncStorage 无缝切换到 react-native-mmkv——一个基于 C++ 原生实现、完全同步调用的高性能键值存储库,让查询缓存以字符串形式落盘,实现"重启不丢缓存、离线秒开页面"。读完本文,你将掌握query-async-storage-persister与 MMKV 的桥接写法、PersistQueryClientProvider的接入方式,以及 MMKV 实例的配置细节与底层行为。


一、为什么把 react-query 缓存持久化到 MMKV

react-query 提供了createAsyncStoragePersister插件,用于把查询缓存(Query Cache)写入一个符合AsyncStorage接口的存储介质。默认情况下它面向@react-native-async-storage/async-storage,但该接口只需三个方法:setItem、getItem、removeItem。

MMKV 的优势在于:

  • 完全同步:storage.set(key, value)、storage.getString(key)等都是同步返回,没有 Promise、没有 Bridge,读写是直接的 JS ↔ C++ 调用,符合"读取一次缓存"的高频场景;
  • 类型丰富:支持string | boolean | number | ArrayBuffer四种取值,天然适合以字符串存储的 JSON 序列化缓存;
  • 原生性能:底层是腾讯开源的 MMKV C++ 实现,读写性能远高于跨线程桥接的 AsyncStorage(仓库主页标注"~30x faster than AsyncStorage",该数据来自 StorageBenchmark 基准项目,仅为社区参考)。

因此,把 react-query 的持久化目标从 AsyncStorage 换成 MMKV,既保持了createAsyncStoragePersister的使用方式不变,又能获得同步、快速的落盘体验。


二、前置条件:安装依赖

本文方案需要两个层面的依赖:

  1. react-native-mmkv 本身(本仓库的安装方式):
npm install react-native-mmkv react-native-nitro-modules cd ios && pod install

若使用 Expo,则:

npx expo install react-native-mmkv react-native-nitro-modules npx expo prebuild
  1. react-query 的持久化插件(下文核心步骤)。

注意:react-native-mmkv V4 基于 Nitro Modules 架构,安装时需保证react-native-nitro-modules已正确链接;从 V3 升级请参考 V4 升级指南。


三、核心步骤一:安装 react-query 持久化包

执行以下命令,安装 TanStack Query 的持久化辅助包:

yarn add @tanstack/query-async-storage-persister @tanstack/react-query-persist-client

两个包的分工:

  • @tanstack/query-async-storage-persister:提供createAsyncStoragePersister(...),把符合 AsyncStorage 接口的存储对象包装成 react-query 可用的Persister;
  • @tanstack/react-query-persist-client:提供PersistQueryClientProvider根组件,负责在应用启动时恢复缓存、运行时持续持久化。

四、核心步骤二:编写 MMKV 适配器(clientStorage)

createAsyncStoragePersister需要一个实现setItem / getItem / removeItem的存储对象。由于 MMKV 本身是同步 API,这个适配器写起来非常直接:

import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister' import { createMMKV } from "react-native-mmkv" const storage = createMMKV() const clientStorage = { setItem: (key, value) => { storage.set(key, value); }, getItem: (key) => { const value = storage.getString(key); return value === undefined ? null : value; }, removeItem: (key) => { storage.remove(key); }, }; export const clientPersister = createAsyncStoragePersister({ storage: clientStorage });

代码中的几个关键细节:

  • createMMKV()的默认行为:无参调用会创建一个 ID 为mmkv.default的默认实例(见 createMMKV.ts 与 MMKVFactory.nitro.ts 的@default 'mmkv.default')。建议将storage与clientPersister在模块顶层导出,全应用复用同一个实例,而不是每次渲染都新建。
  • getItem必须把undefined转成null:MMKV 的getString在键不存在时返回undefined(接口签名见 MMKV.nitro.ts),而 AsyncStorage 接口约定"键不存在返回null"。value === undefined ? null : value正是为了满足这一契约,避免 persister 把undefined误当作合法值处理。
  • 返回值类型:react-query 持久化的缓存内容是 JSON 序列化后的字符串,storage.set(key, value)写入的正是字符串类型;set方法同时支持boolean | number | ArrayBuffer,但此处无需使用。

从源码看,MMKV 的set / getString / remove均为同步方法,因此适配器无需async/await,也无需返回 Promise——这比基于 AsyncStorage 的异步适配器更简单直接。


五、核心步骤三:用 PersistQueryClientProvider 接入根组件

创建好clientPersister后,在根组件(如App.tsx)中用PersistQueryClientProvider替换普通的QueryClientProvider:

import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client' const App = () => { return ( <PersistQueryClientProvider persistOptions={{ persister: clientPersister }}> {...} </PersistQueryClientProvider> ); };

persistOptions.persister即上一步导出的clientPersister。这样,应用每次启动时:

  1. PersistQueryClientProvider会先从 MMKV 中读取上一次保存的缓存(走clientStorage.getItem);
  2. 恢复为可用的 Query Cache,未过期的查询无需重新请求即可立即渲染;
  3. 运行时查询状态的任何变化都会经clientStorage.setItem / removeItem写回 MMKV。

提示:persistOptions还支持maxAge(缓存最大存活时间)、buster(缓存失效标识)等可选参数,可按 TanStack Query 官方文档的createAsyncStoragePersister说明按需配置。


六、源码级深入:MMKV 实例的配置与行为

6.1 可配置项(Configuration)

createMMKV(configuration?)接受完整的配置对象,相关类型定义见 MMKVFactory.nitro.ts:

配置项类型默认值说明
idstring'mmkv.default'实例 ID,多实例场景必须使用不同 ID
pathstringundefined存储根目录,默认$(Documents)/mmkv/;iOS 上配置了 AppGroup 且未指定 path 时自动使用 AppGroup 目录
encryptionKeystringundefined加密密钥,AES-128 最长 16 字节,AES-256 最长 32 字节
encryptionType'AES-128' \| 'AES-256''AES-128'加密算法
mode'single-process' \| 'multi-process''single-process'多进程模式(App Clip、扩展、后台服务等)
readOnlybooleanfalse只读模式,只允许读,set会抛错
compareBeforeSetbooleanfalse写入前先比较新旧值,相等则跳过文件写入,作为可选性能优化
recoveryStrategy'discard-on-error' \| 'recover-on-error'undefined存储出现 CRC/长度错误时的恢复策略

针对 react-query 持久化场景,常见进阶写法:

// 多用户场景:按用户隔离查询缓存 export const queryStorage = createMMKV({ id: `query-cache-${userId}` }) // 敏感查询缓存:加密落盘 export const secureStorage = createMMKV({ id: 'secure-query-cache', encryptionKey: 'my-encryption-key!', encryptionType: 'AES-256', })

6.2 底层方法签名

适配器用到的三个方法在 MMKV.nitro.ts 中定义如下:

  • set(key: string, value: boolean | string | number | ArrayBuffer): void(L44-L44)——空 key 会抛错;
  • getString(key: string): string | undefined(L56-L56)——键不存在返回undefined,这正是适配器需要转null的原因;
  • remove(key: string): boolean(L77-L77)——键被删除返回true,否则返回false。

此外 MMKV 实例还提供getBoolean / getNumber / getBuffer / contains / getAllKeys / clearAll / trim等方法,以及addOnValueChangedListener值变更监听能力,可在需要同步多实例缓存时使用。

6.3 平台与测试环境行为

  • Web 平台:仓库提供独立的 Web 实现(createMMKV.web.ts,底层基于 localStorage 的读写),适配器写法保持一致;
  • 测试环境:在 Jest 等测试环境中,createMMKV会返回内存 Mock 实例(见 createMockMMKV.ts),其getString对缺失键同样返回undefined、set对空 key 抛错,行为与真实实现对齐,因此你的clientStorage适配器可以直接在单测中验证(例如断言"写入后可读回、缺失键返回 null")。

七、实践建议与注意事项

  1. 始终导出并复用实例:在模块顶层创建storage与clientPersister并导出,避免每次渲染新建 MMKV 实例导致重复打开文件句柄。
  2. getItem的null转换不可省略:直接返回storage.getString(key)的undefined会导致 persister 行为异常,务必按文档写法处理。
  3. 持久化内容为字符串:react-query 缓存以 JSON 字符串形式存取,storage.set(key, value)不会做类型推断,直接写入即可;如需额外存布尔/数字型业务数据,MMKV 也原生支持。
  4. 多实例隔离:需要按用户或按模块隔离查询缓存时,使用不同的id创建多个实例,并在适配器中分别引用。
  5. 敏感数据可加密:若查询缓存包含 token、个人信息等,可配置encryptionKey+encryptionType: 'AES-256',密钥长度须符合算法要求。
  6. 清除缓存:需要"登出清缓存"时,可调用storage.clearAll()清空该实例全部键值,或storage.remove(key)定向删除某个缓存条目。

八、同系列方案对比(横向参考)

本仓库 docs 目录下还提供了其他状态管理库的 MMKV 适配模板,可对照参考:

  • Zustand persist-middleware 适配:同样实现setItem / getItem / removeItem三方法,getItem使用value ?? null的写法(MMKV 返回undefined时经空值合并得到null);
  • Redux-persist 适配:由于 redux-persist 接口是异步的,适配器将同步调用包装进Promise.resolve(...)返回;
  • Jotai、MobX、Recoil、TinyBase 等适配:思路一致,均是把各库的存储接口映射到 MMKV 的同步 API 上。

可以看到,React Query 的适配器之所以无需 Promise 包装,正是因为createAsyncStoragePersister直接接受同步风格的 AsyncStorage 兼容对象,这也是三者中写法最简洁的一个。


九、小结

通过三个步骤即可完成 react-query 查询缓存向 MMKV 的迁移:

  1. 安装@tanstack/query-async-storage-persister与@tanstack/react-query-persist-client;
  2. 用createMMKV()+set / getString / remove实现clientStorage,并牢记getItem的undefined → null转换,再经createAsyncStoragePersister生成clientPersister;
  3. 在根组件用PersistQueryClientProvider包裹应用并传入persistOptions.persister。

结合仓库源码(createMMKV.ts、MMKV.nitro.ts、MMKVFactory.nitro.ts)可以看到,这一方案充分利用了 MMKV 同步、快速、类型丰富的特性,让 react-query 的缓存持久化获得原生级的读写性能,且适配代码量极小、易于测试与维护。

【免费下载链接】react-native-mmkv

⚡️ The fastest key/value storage for React Native. ~30x faster than AsyncStorage!

项目地址:https://gitcode.com/gh_mirrors/re/react-native-mmkv
点击查看免费下载
上一篇:如何为 FunASR 的 Paraformer 输出时间戳:带时间戳语音识别指南
下一篇:知识蒸馏在现代AI中的5大应用场景:Awesome Knowledge Distillation实战指南

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

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

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

立即咨询