Docs Menu

Docs HomeRealm

Use Realm React

On this page

  • Overview
  • Setup Realm React
  • Create a Realm Context
  • Setup
  • Using the Realm Provider
  • Usage
  • Dynamically Update the Realm Configuration
  • Use Realm Provider Hooks
  • useRealm
  • useObject
  • useQuery
  • Using the App Provider
  • useApp
  • Using the User Provider
  • useUser
  • Summary

Realm React is an npm package that provides an easy-to-use API to perform common Realm operations, such as querying or 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 will re-render on any changes to data in the realm.

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.

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.

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 a Task insertion object that automatically sets computed values, such as _id and createdAt. This insertion can be forwarded to realm.create to perform an insertion

  • A 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);

Wrap the component needing access to Realm Database, typically the top layer 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.

Tip

Choosing Which Components to Wrap inside the Realm Provider

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.

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>
);
}

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 open:

function AppWrapper() {
const syncConfig = {
user: app?.currentUser,
partitionValue: 'ExpoTemplate',
};
return (
<RealmProvider sync={syncConfig} fallback={() => <LoadingSpinner />}>
<App />
</RealmProvider>
);
}

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;

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.

Tip

See also:

Read the write to a realm documentation to learn more about modifying Realm data.

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>
);
};

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>
);
}

Tip

To learn how to render a filtered or sorted list of tasks, read the Read & Write Data docs.

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>
);
}

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);
};
// ...
}

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.

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>
);
};

Note

The User is Automatically Set for the Sync Configuration

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.

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>
);
};
  • You can set up Realm React on an existing application by installing it through npm or on a new application through the Realm Expo template.

  • A Realm Context opens a realm and contains a RealmProvider and a set of pre-built hooks.

  • A RealmProvider provides access to the configured realm using hooks to display and modify data.

  • The pre-built RealmProvider hooks provide functionality, including interacting with a realm and finding realm object(s).

  • The AppProvider instantiates a new App and provides its child components access to the App instance.

  • You can use the useApp() hook to access the instantiated App within child components.

  • The UserProvider renders it's child components if the user has logged in and renders a fallback component if the user has not logged in.

  • You can use the useUser() hook to gain access to the logged-in user within any child components of the UserProvider.

←  Quick Start with Expo - React Native SDKRealm Fundamentals - React Native SDK →
Give Feedback
© 2022 MongoDB, Inc.

About

  • Careers
  • Investor Relations
  • Legal Notices
  • Privacy Notices
  • Security Information
  • Trust Center
© 2022 MongoDB, Inc.