@realm/react Reference
On this page
@realm/react is an npm package that provides an easy-to-use API to perform common Realm operations, such as querying, writing to a realm, and listening to realm objects.
@realm/react
helps you avoid creating boilerplate code, such as creating
your own listeners and state management. @realm/react
provides access to
Realm database through a set of hooks that update React state when the Realm data changes.
This means that components using these hooks re-render on any changes to data
in the realm.
Note
Using @realm/react with Realm JS Version 11
To use Realm JS version 11.0.0 or higher with @realm/react, you must use @realm/react
to version
0.4.0
or higher.
Setup @realm/react
To set up @realm/react
, you can either start from scratch with a new application
using the Realm Expo template
or install @realm/react
for an existing React Native application.
Create a New App with @realm/react
If you don't have an existing application, we recommend developing it with
the Realm Expo template.
The Realm Expo template allows you to bootstrap your application with
Expo and @realm/react
preconfigured.
To initialize the Realm Expo template, read the Quick Start with Expo documentation.
Add @realm/react to an Existing App
To install @realm/react
on an existing React Native application, run the
following command in your terminal from the root of your application
where your package.json
file is located:
npm install @realm/react
createRealmContext()
The createRealmContext()
method creates a React Context object for a realm with a given Realm.Configuration. The Context
object contains the
following:
A Context Provider component that wraps around a component and provides any of its child components with access to the hooks.
Various pre-built Hooks that you can use to access the opened realm, query the realm, etc.
Setup
We recommend creating a file where you will define a Realm object type, a Realm
configuration, and create a Realm Context
. At the top of the file, import
Realm and the createRealmContext()
method.
import {Realm, createRealmContext} from '@realm/react';
Next, define a Object Schema using a JavaScript class. The Task
class below contains the following:
A
generate()
method that returns aTask
insertion object that automatically sets computed values, such as_id
andcreatedAt
. This insertion can be forwarded torealm.create
to perform an insertionA
schema
property that defines this Object Schema. Read the Define a Realm Object Schema documentation to learn more.
export class Task extends Realm.Object { _id!: Realm.BSON.ObjectId; description!: string; isComplete!: boolean; createdAt!: Date; // the Task.generate() method creates Task objects with fields with default values static generate(description: string) { return { _id: new Realm.BSON.ObjectId(), description, isComplete: false, createdAt: new Date(), }; } // To use a class as a Realm object type, define the object schema on the static property "schema". static schema = { name: 'Task', primaryKey: '_id', properties: { _id: 'objectId', description: 'string', isComplete: {type: 'bool', default: false}, createdAt: 'date', }, }; }
Finally, create a Realm.Configuration
object and set its schema
property
to the classes you have created. Pass the configuration object to the
createRealmContext()
method. Export the return value of
createRealmContext()
, so you can use the Context
object in other files.
const config = { schema: [Task], }; export default createRealmContext(config);
<RealmProvider>
Wrap the component needing access to Realm Database, typically near the top
of your application, with the <RealmProvider>
component included in the
Context
object, which was returned from createRealmContext()
. The
<RealmProvider>
provides child components access to the configured
Realm through the hooks included in the Context
object.
For simple use-cases, you may want to wrap your entire application in the
<RealmProvider>
component, such as the example below. For additional security,
you may only want to give access to the opened realm to specific screens, or
after the user has logged-in.
Usage
Import the Context
object that you created. In the example below, the
Context
object is called TaskContext
since it refers to the Realm Context
of
the Task. You can Destructure
the TaskContext
object to get its <RealmProvider>
.
import TaskContext from './models/Task'; const {RealmProvider} = TaskContext;
Wrap the <RealmProvider>
around the component that you want
to give access to the configured realm. In the example below, we give the entire
app access to the realm by wrapping the <RealmProvider>
around
the App
component, which renders the application.
function AppWrapper() { return ( <RealmProvider> <App /> </RealmProvider> ); }
Dynamically Update the Realm Configuration
You can dynamically update the Realm configuration by setting
props on the <RealmProvider>
component. The props you set on the <RealmProvider>
will overwrite any
property passed into createRealmContext()
.
In the following example, we update the <RealmProvider>
with a sync
configuration and a fallback
property that is used to render a temporary LoadingSpinner
component while
waiting for Device Sync to fully synchronize data before opening the realm:
function AppWrapper() { const syncConfig = { user: app?.currentUser, partitionValue: 'ExpoTemplate', }; return ( <RealmProvider sync={syncConfig} fallback={() => <LoadingSpinner />}> <App /> </RealmProvider> ); }
The Realm Hooks
Once you have wrapped your component with your <RealmProvider>
, your component
and its child components will have access to the useRealm()
,
useObject()
, and useQuery()
hooks.
Import the Task
model and Context
object that you created. In the example below, the
Context
object, called TaskContext
, refers to the Context
of
the Task. Destructure
the TaskContext
object to get its hooks.
import TaskContext, {Task} from './models/Task'; const {useRealm, useQuery, useObject} = TaskContext;
useRealm()
The useRealm()
hook returns the opened realm instance.
The handleAddTask()
method of the App
component writes to the realm
returned by the useRealm()
hook in the following example.
const realm = useRealm(); const handleAddTask = useCallback( (description: string): void => { if (!description) { return; } realm.write(() => { realm.create('Task', Task.generate(description)); }); }, [realm], );
The Realm.create() call invokes the Task.generate()
method defined in the Task
class. This method instantiates a JavaScript object
with default values for the _id
, isComplete
, and createdAt
properties.
To learn more about modifying Realm data, refer to Write Transactions.
useObject()
The useObject()
hook returns a Realm object for a given
primary key. You can invoke it with the class
model definition (this will add types to the returned object in TypeScript) or
the class name as a string and the primary key. The useObject()
method
returns null if the object doesn't exist or you have deleted it. The hook will
automatically subscribe to updates and re-render the component using the hook on
any change to the object.
In the following example, the useObject()
hook retrieves a Task
object,
and its description is rendered in the UI.
const SampleTask = ({_id}) => { const myTask = useObject(Task, _id); return ( <View> <Text>Task: {myTask?.description} </Text> </View> ); };
useQuery()
The useQuery()
hook returns a collection of realm objects of a given type.
Like useObject
, it is either invoked with the Object Schema class or the model
name as a string. The useQuery()
method subscribes to updates to any
objects in the collection and re-renders the component using it on any change to the query results.
In the following example, of a TaskList
component, The Task
class is passed to the useQuery()
and the tasks are set as a data
prop
of a FlatList component.
function TaskList({onToggleTaskStatus, onDeleteTask}) { const tasks = useQuery(Task); return ( <View style={styles.listContainer}> <FlatList data={tasks} keyExtractor={task => task._id.toString()} renderItem={({item}) => ( <TaskItem description={item.description} isComplete={item.isComplete} onToggleStatus={() => onToggleTaskStatus(item)} onDelete={() => onDeleteTask(item)} /> )} /> </View> ); }
To learn how to render a filtered or sorted list of tasks, read the CRUD - Read docs.
<AppProvider>
To use Realm features such as authentication and sync, use the
<AppProvider>
to initiate a new Realm.App. Wrap the
<AppProvider>
outside of the <RealmProvider>
and any components which need
access to the useApp hook.
import { AppProvider } from '@realm/react' function AppWrapper() { return ( <AppProvider id={appId}> <RealmProvider> <App /> </RealmProvider> </AppProvider> ); }
useApp()
The useApp()
hook provides access to the Realm.App
instance.
In the following example, we call useApp()
within a LoginComponent
, and
then use the app instance to log in with email/password authentication.
import {useApp} from '@realm/react'; function LoginComponent({}) { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const app = useApp(); const signIn = async () => { const credentials = Realm.Credentials.emailPassword(email, password); await app.logIn(credentials); }; // ... }
<UserProvider>
The <UserProvider>
provides a Realm user for its
child components to access.
The <UserProvider>
:
contains an optional
fallback
property that renders a Login component when the user has not authenticated.renders its child components only if the user is logged in or has no fallback property.
When the <UserProvider>
wraps the <RealmProvider>
, the <RealmProvider>
automatically sets the logged-in user for your sync configuration. This means
you do not need to specify your user in your sync configuration object.
In the following example, we pass a Login component to the fallback property of
<UserProvider>
. Once the user has logged in, the Login component disappears
from the view, and the App
is rendered. We wrap the App
in a
<RealmProvider>
with a sync configuration to give the App
access to a
synced realm. If the user logs out, the application falls back to
the Login component.
import { AppProvider, UserProvider } from '@realm/react' const AppWrapper = () => { return ( <AppProvider id={appId}> <UserProvider fallback={LoginComponent}> {/* After login, user will be automatically populated in realm configuration */} <RealmProvider sync={{partitionValue: 'SamplePartition'}}> <App /> </RealmProvider> </UserProvider> </AppProvider> ); };
useUser()
The useUser()
hook provides access to the logged-in user.
In the following example, we call useApp()
within a SampleTask
component and display the logged-in user's _id
.
import {useUser} from '@realm/react'; const SampleTask = ({_id}) => { // Access the logged in user using the useUser hook const user = useUser(); const myTask = useObject(Task, _id); return ( <View> <Text> The task {myTask?.description} was created by user id: {user?.id} </Text> </View> ); };