You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
    
  • 应用组件持续重渲染

疑问

  1. 遗漏了什么配置?
  2. 如何实现客户端跨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;

原因分析

  1. 离线重启后,Realm仍会尝试连接MongoDB服务器获取位置信息,网络不通时触发错误,导致组件重渲染
  2. 当前配置未持久化「暂停同步」的状态,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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 23:53:34