Manage a Sync Session - React Native SDK
On this page
When you use Atlas Device Sync, the React Native SDK syncs data with Atlas in the background using a sync session. A sync session starts whenever you open a synced realm.
Prerequisites
Before you can manage a sync session, you must perform the following:
Wrap components that use the
useRealm()
hook for a synced realm with theAppProvider
,UserProvider
, andRealmProvider
components. For more information on configuring and opening a synced realm, refer to Open a Synced Realm.
Access Sync Session
Access a synced realm in a component with the useRealm()
hook.
Access the sync session with the realm's Realm.syncSession property.
import React, {useEffect} from 'react'; import {Context} from '../RealmConfig'; const {useRealm} = Context; function AccessSyncSession() { const realm = useRealm(); async function workWithSyncSession() { const {syncSession} = realm; // Do stuff with sync session... } // ... }
Pause or Resume a Sync Session
Opening a synced realm starts a sync session. You can pause and resume the realm's sync session. If you have more than one open realm, pause does not affect the other realms' sync sessions.
To pause synchronization, use the Realm.syncSession.pause() method. To resume synchronization, use the Realm.syncSession.resume() method.
import React, {useEffect, useState} from 'react'; import {Context} from '../RealmConfig'; const {useRealm} = Context; function ToggleSyncSession() { const realm = useRealm(); const [isPaused, setIsPaused] = useState(false); async function toggleSyncSession() { if (isPaused) { await realm.syncSession?.resume(); } else { await realm.syncSession?.pause(); } setIsPaused(!isPaused); } return ( <Button title={isPaused ? 'Pause Sync' : 'Unpause Sync'} onPress={toggleSyncSession} /> ); }
When to Pause a Sync Session
For most applications, there is no need to manually pause and resume a sync session. However, there are a few circumstances under which you may want to pause or suspend a sync session:
You only want to sync after the user takes a specific action
You only want to sync during a certain time of the day
You don't want to attempt to sync when there is poor network connectivity
You want to explicitly force a sync session to connect
In the case of poor network connectivity, continually trying to establish a network connection can drain the user's device battery.
The case of explicitly forcing a sync session to connect is most commonly related to being offline for some time. The sync client attempts to connect, and upon failure, goes into exponential backoff. After being offline for a long time, the client may not immediately reconnect. Pausing and resuming the sync session explicitly forces the connection.
When you do pause a sync session, keep these things in mind:
If the client may be offline longer than the client maximum offline time, the client will be unable to resume syncing and must perform a client reset.
Pausing a sync session pauses it in both directions. Changes that your app makes on the device do not sync with the backend, and changes to the data in the backend or on other devices do not sync to the device. There is no way to pause only uploads or pause only downloads.
Do not pause a sync session if you want a client to permanently stop syncing with the backend. To permanently stop syncing, copy the contents of the synced realm into a non-synced realm, and use the non-synced realm in the client.
Do not pause sync to stop syncing for indefinite time periods or time ranges in months and years. The functionality is not designed or tested for these use cases. You could encounter a range of issues when using it this way.
Check Upload & Download Progress for a Sync Session
To check the upload and download progress for a sync session, add a progress notification using the Realm.syncSession.addProgressNotification() method.
The Realm.syncSession.addProgressNotification()
method takes in the following three parameters:
A
direction
parameter. Set to"upload"
to register notifications for uploading data. Set to"download"
to register notifications for downloading data.A
mode
parameter. Set to"reportIndefinitely"
for the notifications to continue until the callback is unregistered using Realm.syncSession.removeProgressNotification(). Set to"forCurrentlyOutstandingWork"
for the notifications to continue until only the currently transferable bytes are synced.A callback function parameter that has the arguments
transferred
andtransferable
.transferred
is the current number of bytes already transferred.transferable
is the total number of bytes already transferred plus the number of bytes pending transfer.
Note
Flexible Sync progress notifications are not yet fully supported. When using Flexible Sync, downloads only report notifications after changes are integrated. Partition-Based Sync provides ongoing notifications as changes progress downloading. Uploads report ongoing progress notifications for both Sync Modes.
The following example registers a callback on the syncSession
to
listen for upload events indefinitely. The example writes to the realm and
then unregisters the syncSession
notification callback.
import React, {useEffect, useState} from 'react'; import {SyncedRealmContext} from '../RealmConfig'; const {useRealm} = SyncedRealmContext; import {Text} from 'react-native'; function CheckUploadProgress() { const realm = useRealm(); const [uploadProgressPercent, setUploadProgressPercent] = useState(0); useEffect(() => { const progressNotificationCallback = (transferred, transferable) => { // Convert decimal to percent with no decimals // (e.g. 0.6666... -> 67) const percentTransferred = parseFloat((transferred / transferable).toFixed(2)) * 100; setUploadProgressPercent(percentTransferred); }; // Listen for changes to connection state realm.syncSession?.addProgressNotification( Realm.ProgressDirection.Upload, Realm.ProgressMode.ReportIndefinitely, progressNotificationCallback, ); // Remove the connection listener when component unmounts return () => realm.syncSession?.removeProgressNotification( progressNotificationCallback, ); // Run useEffect only when component mounts }, []); return <Text>Percent Uploaded: {uploadProgressPercent} %</Text>; }
import React, {useEffect, useState} from 'react'; import {Context} from '../RealmConfig'; const {useRealm} = Context; import {Text} from 'react-native'; function CheckUploadProgress() { const realm = useRealm(); const [uploadProgressPercent, setUploadProgressPercent] = useState(0); useEffect(() => { const progressNotificationCallback: Realm.ProgressNotificationCallback = ( transferred, transferable, ) => { // Convert decimal to percent with no decimals // (e.g. 0.6666... -> 67) const percentTransferred = parseFloat((transferred / transferable).toFixed(2)) * 100; setUploadProgressPercent(percentTransferred); }; // Listen for changes to connection state realm.syncSession?.addProgressNotification( Realm.ProgressDirection.Upload, Realm.ProgressMode.ReportIndefinitely, progressNotificationCallback, ); // Remove the connection listener when component unmounts return () => realm.syncSession?.removeProgressNotification( progressNotificationCallback, ); // Run useEffect only when component mounts }, []); return <Text>Percent Uploaded: {uploadProgressPercent} %</Text>; }
Check the Network Connection
Realm's offline-first design means that you generally don't need to check the current network connection state since data syncs in the background when a connection is available. That said, the Realm SDK provides methods to get the current state of the network connection to the server.
To check the current state of the connection to the server, call
Realm.syncSession.isConnected().
This method returns a boolean that is true
if there is a network connection and
the sync session is active.
To listen for connection state changes, call Realm.syncSession.addConnectionNotification(), passing a callback function to handle network changes as the argument. To unregister the listener, pass the same callback function to Realm.syncSession.removeConnectionNotification().
import React, {useState, useEffect} from 'react'; import {SyncedRealmContext} from '../RealmConfig'; const {useRealm} = SyncedRealmContext; import {Text} from 'react-native'; function CheckNetworkConnection() { const realm = useRealm(); const [isConnected, setIsConnected] = useState( realm.syncSession?.isConnected(), ); useEffect(() => { const connectionNotificationCallback = (newState, oldState) => { console.log('Current connection state: ' + newState); console.log('Previous connection state: ' + oldState); setIsConnected(realm.syncSession?.isConnected()); }; // Listen for changes to connection state realm.syncSession?.addConnectionNotification( connectionNotificationCallback, ); // Remove the connection listener when component unmounts return () => realm.syncSession?.removeConnectionNotification( connectionNotificationCallback, ); // Run useEffect only when component mounts }, []); return ( <Text> {isConnected ? 'Connected to Network' : 'Disconnected from Network'} </Text> ); }
import React, {useState, useEffect} from 'react'; import {Context} from '../RealmConfig'; const {useRealm} = Context; import {Text} from 'react-native'; function CheckNetworkConnection() { const realm = useRealm(); const [isConnected, setIsConnected] = useState( realm.syncSession?.isConnected(), ); useEffect(() => { const connectionNotificationCallback: Realm.ConnectionNotificationCallback = (newState, oldState) => { console.log('Current connection state: ' + newState); console.log('Previous connection state: ' + oldState); setIsConnected(realm.syncSession?.isConnected()); }; // Listen for changes to connection state realm.syncSession?.addConnectionNotification( connectionNotificationCallback, ); // Remove the connection listener when component unmounts return () => realm.syncSession?.removeConnectionNotification( connectionNotificationCallback, ); // Run useEffect only when component mounts }, []); return ( <Text> {isConnected ? 'Connected to Network' : 'Disconnected from Network'} </Text> ); }
Multiplex Sync Sessions
Enable session multiplexing to consolidate multiple sync sessions of a Realm app. Only use session multiplexing if you see errors about reaching the file descriptor limit, and you know you are using many sync sessions.
To enable session multiplexing, call Realm.App.Sync.enableSessionMultiplexing() with your Realm.App.
import React, {useEffect} from 'react'; import {Context} from '../RealmConfig'; import {AppProvider, UserProvider, useUser, useApp, Realm} from '@realm/react'; function AppWrapper() { return ( <AppProvider id={APP_ID}> <UserProvider fallback={<LogIn />}> <RealmWrapper> <RestOfApp /> </RealmWrapper> </UserProvider> </AppProvider> ); } type RealmWrapperProps = { children: React.ReactNode; }; function RealmWrapper({children}: RealmWrapperProps) { const app = useApp(); Realm.App.Sync.enableSessionMultiplexing(app); return <RealmProvider sync={{flexible: true}}>{children}</RealmProvider>; }