React Native
Persist sessions and connect offline replicas without relying on browser storage APIs.
Bring sessions and replicas to native apps
The React Native package supplies session-storage and native-SQLite adapter contracts without bundling a runtime database.
Applications retain control of Expo/native dependencies while FFDB owns session validation and replica semantics.
Use it for React Native or Expo apps that need durable sessions or offline SQLite replicas.
Requirements for React Native
- Prerequisite — Version-matched client, sync-client, and react-native SDK packages.
- Prerequisite — An encrypted async key-value store and SQLite runtime supporting STRICT tables, upsert, and atomic transactions.
- Required value — AsyncKeyValueStorage, NativeSQLiteDriver, database location, session key, and lifecycle/network triggers.
- Required value — A user-scope strategy that prevents different identities sharing visible cached rows.
Install the native integration
React Native uses exact-version @ffdb/client, @ffdb/sync-client, and @ffdb/react-native npm packages. The matching tag provides signed offline tarballs. The integration supplies contracts and adapters; your app still chooses its SecureStore-like and SQLite implementations.
VERSION=0.3.0
npm install --save-exact "@ffdb/client@$VERSION" \
"@ffdb/sync-client@$VERSION" "@ffdb/react-native@$VERSION"Runtime adapters
@ffdb/react-native supplies contracts for asynchronous session storage and native SQLite replicas. It does not bundle a direct Expo SQLite or SecureStore implementation; wrap the runtime APIs your application already owns.
- AsyncKeyValueStorage implements async getItem, setItem, and removeItem; inject a SecureStore-like encrypted implementation for refresh tokens.
- NativeSQLiteDriver implements parameterized execute plus a transaction callback that keeps every callback statement on the same atomic transaction.
- The SQLite runtime must support STRICT tables and ON CONFLICT ... DO UPDATE, which the replica uses for metadata, rows, pending mutations, and rejections.
- NativeSQLiteReplica owns reserved __ffdb_client_* tables in that local database.
- @ffdb/client owns HTTP and @ffdb/sync-client owns snapshot/push/pull orchestration.
- getRow and listRows return decoded local records without exposing the private SQLite connection.
import { FFDBClient } from "@ffdb/client";
import {
NativeSQLiteReplica,
ReactNativeSessionStore,
type AsyncKeyValueStorage,
type NativeSQLiteDriver,
} from "@ffdb/react-native";
import { OfflineSyncClient } from "@ffdb/sync-client";
declare const secureStorage: AsyncKeyValueStorage;
declare const sqliteDriver: NativeSQLiteDriver;
const ffdb = new FFDBClient({
baseUrl: "https://data.example.com",
projectId: "your-project-id",
sessionStore: new ReactNativeSessionStore(secureStorage),
});
const replica = new NativeSQLiteReplica(sqliteDriver);
await replica.initialize();
export const sync = new OfflineSyncClient(ffdb, replica);
export const readDraft = (id: string) => sync.getRow("drafts", id);
export const listDrafts = () => sync.listRows("drafts");Schedule mobile sync
The package intentionally does not import NetInfo, AppState, Expo SQLite, or SecureStore. The application owns those dependencies and decides when background network work is permitted.
- Wire onNetworkAvailable to your NetInfo-equivalent online transition.
- Wire onApplicationActive to the React Native AppState-equivalent active transition.
- Do not run a tight polling loop while backgrounded.
- A transient initialize() failure is retryable; the replica clears its failed initialization promise before the next operation.
import type { SyncMutation } from "@ffdb/client";
export async function onNetworkAvailable(): Promise<void> {
await sync.sync();
}
export async function onApplicationActive(): Promise<void> {
await sync.sync();
}
export function onUserMutation(mutation: SyncMutation): Promise<void> {
return sync.mutate(mutation);
}React Native workflow
- 1. Wrap the runtime storage in AsyncKeyValueStorage.
- 2. Wrap SQLite execute and transaction APIs in NativeSQLiteDriver.
- 3. Construct ReactNativeSessionStore and NativeSQLiteReplica.
- 4. Initialize the replica and construct OfflineSyncClient.
- 5. Wire active/online events to bounded sync attempts.
Verify react native
Valid sessions, rows, cursors, and queued mutations persist across app restart without browser APIs.
Troubleshoot react native
- Persisted session JSON is invalid — the store removes it and requires sign-in.
- Initialization fails transiently — fix the runtime cause and retry; the adapter clears the failed promise.
Continue from React Native
- Test cold-start and account-switch behavior.
- Implement rejected-mutation UI.