在React Native的Relay Modern中配置多层网络层实现离线优先
当然可以实现这种「优先返回本地离线数据+后台自动同步网络数据」的需求,我之前在React Native项目里用Relay Modern落地过类似方案,给你拆解下具体实现思路和步骤:
核心思路
本质是要自定义一个复合Relay网络层,把「本地Schema查询层」和「真实网络请求层」结合起来:
- 接收到Relay的查询请求时,先从本地数据库(Realm/SQLite等)取数据并立即返回,让组件快速渲染离线内容
- 在后台异步发起真实网络请求,拿到最新数据后更新本地数据库
- 数据库更新完成后,通知Relay刷新组件,展示最新的网络数据
具体实现步骤
1. 搭建本地Schema与数据存储
首先要确保本地的GraphQL Schema和服务端完全一致,这样Relay的查询逻辑可以无缝复用:
- 复制服务端的GraphQL Schema定义,创建本地Schema文件
- 基于Realm/SQLite实现对应的数据读写逻辑,编写Schema里每个字段的Resolver(比如
Query.user对应从本地数据库查用户信息) - 借助
relay-local-schema创建本地的Relay Network实例,用来处理本地查询
2. 自定义复合网络层
写一个包装后的fetchQuery函数,串联本地查询和网络查询的逻辑:
import { Environment, commitLocalUpdate } from 'react-relay'; import { fetchQuery as localFetch } from './local-network-layer'; // 本地网络层 import { fetchQuery as networkFetch } from './remote-network-layer'; // 真实网络层 // 自定义合并后的fetchQuery export async function fetchQuery( environment: Environment, operation: any, variables: any, cacheConfig?: any, ) { // 第一步:优先返回本地离线数据 const localData = await localFetch(environment, operation, variables, cacheConfig); // 第二步:后台异步发起网络请求,不阻塞UI (async () => { try { const remoteData = await networkFetch(environment, operation, variables, cacheConfig); // 更新本地数据库,把网络最新数据存进去 await syncLocalDatabase(operation, variables, remoteData); // 第三步:通知Relay刷新组件,展示最新数据 commitLocalUpdate(environment, store => { // 根据查询类型更新Relay Store,比如更新用户节点的字段 const user = store.get(variables.userId); if (user) { user.setValue(remoteData.user.name, 'name'); // 其他字段同理更新 } }); } catch (error) { console.error('数据同步失败:', error); // 这里可以加入重试逻辑,比如指数退避重试 } })(); // 先返回本地数据,让组件快速渲染 return localData; }
3. 处理同步细节与状态提示
- ** stale状态标记**:给本地数据加一个
isStale字段,返回数据时传递给组件,让组件可以显示「正在同步」的提示(比如顶部的加载条) - 冲突处理:如果本地有未同步的修改,要定义冲突策略(比如以网络数据为准,或者合并本地修改后再同步)
- 离线写操作:如果是Mutation请求(比如修改用户信息),离线时要把操作加入队列,等网络恢复后再批量同步到服务端
关键注意点
- 本地Schema必须和服务端严格对齐,包括字段名、类型、参数,否则Relay会抛出查询不匹配的错误
- 本地数据库的更新要触发Relay的Store更新,不然组件不会自动刷新最新的网络数据
- 异步网络请求要做好错误捕获和重试,避免因网络波动导致数据同步失败
- 本地查询要保证性能,尽量用异步数据库操作,不要阻塞UI线程
内容的提问来源于stack exchange,提问作者jay shah
相关产品推荐
相关产品推荐

