Expo
Zero has built-in support for Expo and React Native using the expo-sqlite
and op-sqlite
packages.
Prerequisites
The crypto
API is not available in React Native, so we need to polyfill it.
First, install the expo-crypto
package. See the expo-crypto docs for more information.
npx expo install expo-crypto
Then create a new file in your project, e.g. lib/crypto.ts
, and add the following code:
// lib/crypto.ts
import * as Crypto from 'expo-crypto';
declare const global: {
crypto: {
getRandomValues(array: Uint8Array): Uint8Array;
randomUUID(): string;
};
};
export function bootCryptoPolyfill() {
if (global.crypto) {
return;
}
global.crypto = {
getRandomValues(array: Uint8Array) {
return Crypto.getRandomValues(array);
},
randomUUID() {
return Crypto.randomUUID();
},
};
}
This will allow you to use the crypto
API in your React Native project such as crypto.getRandomValues()
and crypto.randomUUID()
.
Expo SQLite
For more information on how to use the expo-sqlite
package, see the expo-sqlite docs.
Remember to install the dependencies:
npx expo install expo-sqlite
OP-SQLite
For more information on how to use the op-sqlite
package, see the op-sqlite docs.
Per the docs, if you are using Expo, you cannot add this library on a expo-go app, you need to pre-build your app.
npx expo install @op-engineering/op-sqlite
npx expo prebuild
Usage
In your mobile app's root index or layout file, wrap your app's with the ZeroProvider
component:
// apps/my-app/_layout.tsx
import '../globals.css';
import {Zero} from '@rocicorp/zero';
import {ZeroProvider} from '@rocicorp/zero/react';
import {createExpoSQLiteStore} from '@rocicorp/zero/expo';
// or if using op-sqlite
// import { createOPSQLiteStore } from '@rocicorp/zero/op-sqlite';
import {Stack} from 'expo-router';
import {useMemo} from 'react';
import {schema} from '../lib/schema'; // or wherever you have your schema
export const unstable_settings = {
// Ensure that reloading on `/modal` keeps a back button present.
initialRouteName: '(tabs)',
};
export default function RootLayout() {
// In production, memoize the Zero instance so it's only created once per app lifecycle
// Note: If you intend to use Expo Web, you should use kvStore: 'mem' or 'idb' with a check like
// const store = Platform.OS === 'web' ? 'idb' : createExpoSQLiteStore;
const z = useMemo(
() =>
new Zero({
userID: 'your-user-id',
auth: 'your-auth-token',
server: process.env.EXPO_PUBLIC_SERVER_URL, // see https://docs.expo.dev/guides/environment-variables/
kvStore: createExpoSQLiteStore,
// kvStore: createExpoSQLiteStore, // or if using op-sqlite
schema,
}),
[userId, authToken],
);
if (!z) {
return null;
}
return (
<ZeroProvider zero={z}>
<Stack>
<Stack.Screen name="(tabs)" options={{headerShown: false}} />
<Stack.Screen name="modal" options={{presentation: 'modal'}} />
</Stack>
</ZeroProvider>
);
}
Interact with the Zero instance in your components using the zero/react
package. Please see the React docs for more details.
import {useQuery, useZero} from '@rocicorp/zero/react';
function IssueList() {
const z = useZero();
let issueQuery = z.query.issue
.related('creator')
.related('labels')
.limit(100);
const userID = selectedUserID();
if (userID) {
issueQuery = issueQuery.where('creatorID', '=', userID);
}
const [issues, issuesDetail] = useQuery(issueQuery);
// Your component React Native JSX
return <View>...</View>;
}
Complete quickstart here: COMING SOON