React Native Realm灵活同步:离线重启报错与同步持久禁用问题
问题与解决方案:Realm Flexible Sync 离线重启同步错误与持久禁用同步
业务场景需求
- 用户在线登录后,可在客户端暂停同步
- 离线(无网络)状态下使用应用2-3天,支持本地创建、更新文档
- 离线周期结束或完成更新后可恢复同步
当前问题
已配置Flexible Sync,在线时登录、暂停/恢复同步功能正常,但离线重启App后:
- 缓存用户存在,本地Realm可正常查询文档
- 数秒后控制台反复抛出错误:
[error] App: request location failed (CustomError -1): request to ``https://realm.mongodb.com/api/client/v2.0/app/*[app-id]*/location`` failed, reason: Network request failed - 应用组件持续重渲染
疑问
- 遗漏了什么配置?
- 如何实现客户端跨App重启持久禁用同步?
现有AppWrapper代码
import { useState } from 'react'; import { AppProvider, UserProvider, useApp } from '@realm/react'; import Realm from 'realm'; import { schemas } from '../../models'; import { RealmProvider } from '@realm/react'; import { OpenRealmBehaviorType, OpenRealmTimeOutBehavior, SyncError } from 'realm'; import { LoginScreen } from '../LoginScreen'; import SyncFallback from '../SyncFallback'; const AppWrapper: React.FC<{ appId: string; children: React.ReactNode; }> = ({ appId, children }) => { const [syncError, setSyncError] = useState<SyncError | null>(null); const realmAccessBehavior: Realm.OpenRealmBehaviorConfiguration = { type: OpenRealmBehaviorType.OpenImmediately, timeOutBehavior: OpenRealmTimeOutBehavior?.OpenLocalRealm ?? 'openLocalRealm', timeOut: 1000, }; return ( <AppProvider id={appId}> <UserProvider fallback={<LoginScreen />}> <RealmProvider schema={schemas} fallback={<SyncFallback err={syncError} />} sync={{ flexible: true, existingRealmFileBehavior: { type: OpenRealmBehaviorType.OpenImmediately, }, newRealmFileBehavior: realmAccessBehavior, }} > {children} </RealmProvider> </UserProvider> </AppProvider> ); }; export default AppWrapper;
原因分析
- 离线重启后,Realm仍会尝试连接MongoDB服务器获取位置信息,网络不通时触发错误,导致组件重渲染
- 当前配置未持久化「暂停同步」的状态,App重启后会自动恢复同步尝试
解决方案
1. 持久化同步状态
使用本地存储(如AsyncStorage或localStorage)保存用户的同步开关状态,确保跨重启保留设置:
// 示例:用AsyncStorage保存同步状态 import AsyncStorage from '@react-native-async-storage/async-storage'; // 保存暂停状态 export const setSyncPaused = async (paused: boolean) => { await AsyncStorage.setItem('realm_sync_paused', JSON.stringify(paused)); }; // 获取暂停状态 export const getSyncPaused = async () => { const value = await AsyncStorage.getItem('realm_sync_paused'); return value ? JSON.parse(value) : false; };
2. 修改RealmProvider配置,动态控制同步
在AppWrapper中读取持久化的同步状态,动态决定是否启用同步:
import { useEffect } from 'react'; const AppWrapper: React.FC<{ appId: string; children: React.ReactNode }> = ({ appId, children }) => { const [syncError, setSyncError] = useState<SyncError | null>(null); const [isSyncPaused, setIsSyncPaused] = useState<boolean>(false); // 初始化时读取持久化状态 useEffect(() => { const fetchSyncState = async () => { const paused = await getSyncPaused(); setIsSyncPaused(paused); }; fetchSyncState(); }, []); const realmAccessBehavior: Realm.OpenRealmBehaviorConfiguration = { type: OpenRealmBehaviorType.OpenImmediately, timeOutBehavior: OpenRealmTimeOutBehavior.OpenLocalRealm, timeOut: 1000, }; return ( <AppProvider id={appId}> <UserProvider fallback={<LoginScreen />}> <RealmProvider schema={schemas} fallback={<SyncFallback err={syncError} />} // 根据状态决定是否启用同步 sync={isSyncPaused ? undefined : { flexible: true, existingRealmFileBehavior: { type: OpenRealmBehaviorType.OpenImmediately, }, newRealmFileBehavior: realmAccessBehavior, // 添加错误处理,避免重复重渲染 onError: (error) => { // 仅在同步未暂停时处理错误,避免离线时触发 if (!isSyncPaused) { setSyncError(error); } }, }} > {/* 传递同步状态控制函数给子组件 */} {React.cloneElement(children as React.ReactElement, { isSyncPaused, setSyncPaused: async (paused: boolean) => { await setSyncPaused(paused); setIsSyncPaused(paused); }, })} </RealmProvider> </UserProvider> </AppProvider> ); };
3. 处理同步错误与组件重渲染
- 在
onError回调中判断同步状态,仅在未暂停时更新错误状态,避免离线时触发不必要的重渲染 - 若已暂停同步,直接忽略网络相关错误
4. 暂停/恢复同步的业务逻辑
在子组件中调用同步控制函数,同时手动操作Realm同步会话:
import { useRealm } from '@realm/react'; const SyncControl = ({ isSyncPaused, setSyncPaused }) => { const realm = useRealm(); const toggleSync = async () => { const newState = !isSyncPaused; await setSyncPaused(newState); if (newState) { // 暂停同步 realm.syncSession?.pause(); } else { // 恢复同步 realm.syncSession?.resume(); } }; return ( <button onClick={toggleSync}> {isSyncPaused ? '恢复同步' : '暂停同步'} </button> ); };
内容的提问来源于stack exchange,提问作者Teacher Tactics
相关产品推荐
相关产品推荐

