Docs Menu
Docs Home
/ /
Atlas Device SDKs
/
/

Providers & Hooks

On this page

  • Getting Started with Providers
  • Props
  • Configure your Providers
  • Working with Providers using Hooks
  • RealmProvider Hooks
  • useRealm()
  • useObject()
  • useQuery()
  • UserProvider Hooks
  • useUser()
  • AppProvider Hooks
  • useApp()
  • useAuth()
  • useEmailPasswordAuth()
  • Create Context with createRealmContext()

The @realm/react library offers custom React components that eliminate the boilerplate needed to develop a React app using JavaScript-based Atlas Device SDKs. The components leverage the Provider design pattern to manage your Atlas connection, user creation and authentication, and data management.

  • AppProvider: Used to connect to your Atlas App Services App Client, including for user authentication.

  • UserProvider: Used to access the logged-in user object.

  • RealmProvider: Used to work with the configured database.

Use these providers to develop with frameworks and for platforms that support a React environment, including: React Native, Web, and Electron.

Like all React components, you call providers using HTML opening and closing tags. Nesting a component within another component's tags creates a parent-child relationship between them, where child components can access the context created by their parent component.

Context refers to the information made accessible by a provider. For example, the RealmProvider context is the Realm database it connects to, so all components nested in the RealmProvider have access to that database.

Components take parameters called props as input, passed into the opening tag. The props passed into a parent component help create the context inherited by the components it wraps. Each Provider has different props you can use for configuration.

Your app's needs determine what providers you use, as all three providers are not always necessary. The example below walks through configuring all three providers. If your app does not need a certain provider, you can skip the steps and omit the code for that provider.

To configure your providers:

  1. Import RealmProvider, AppProvider, and UserProvider from @realm/react.

  2. Configure AppProvider.

    1. Pass your App Services App ID string to the id prop of the AppProvider.

    2. Add other configuration object properties as props to AppProvider as needed.

  3. Configure UserProvider and nest it within AppProvider.

    1. Pass a component that logs in a user to the fallback prop. The app renders this component if there is no authenticated user.

  4. Configure RealmProvider and nest it within UserProvider.

    1. Pass your object models to the schema prop.

    2. If configuring a synced database, use the sync prop. Sync properties are defined by a Sync Config Object.

      To sync data, you must set up a sync subscription. The example below uses an initial subscription, but you can also set up subscriptions in RealmProvider child components.

    3. Add other configuration object properties as props to RealmProvider as needed.

  5. Nest your app components in the providers.

    Once your providers have been configured and nested as described above, nest your app components within the provider whose context it needs to access. Generally, you can nest your components within the RealmProvider to ensure they have access to all three providers' contexts.

The rendering of each component is dependent on the successful execution of its parent components' functionality. For example, while AppProvider is connecting to your app's App Services backend, or if AppProvider is unable to connect, the components it wraps will not render. In these cases, the provider's fallback component is rendered instead.

You must nest the providers as shown below to ensure each has access to its required context:

import React from 'react';
import {AppProvider, UserProvider, RealmProvider} from '@realm/react';
function AppWrapperSync() {
return (
<AppProvider id={APP_ID}>
<UserProvider fallback={LogIn}>
<RealmProvider
schema={[YourObjectModel]}
sync={{
flexible: true,
initialSubscriptions: {
update(subs, realm) {
subs.add(realm.objects(YourObjectModel));
},
},
}}>
<RestOfApp />
</RealmProvider>
</UserProvider>
</AppProvider>
);
}

Note

Exposing more than one database using createRealmContext()

The example above details how to configure and expose a single database using a RealmProvider imported directly from @realm/react. For information about using createRealmContext() to configure a database or exposing more than one database, see Create Context with createRealmContext() below.

To use the provider's context in your app's components, you can use Hooks.

Hooks act as functions used to access states in your app. React offers built-in Hooks you can use either on their own or to build custom Hooks.

There are two important rules to consider when working with Hooks:

  • Hooks can only be used at the top level of a React component.

  • Hooks can only be called in a React component or a custom Hook, not in regular JavaScript functions.

The @realm/react library has custom Hooks for each provider you can use to access a provider's context in the components it wraps.

Type signature
useRealm(): Realm

The useRealm() Hook returns an opened database instance. The database instance gives you access to database methods and properties. For example, you can call realm.write() to add a Realm Object to your database.

To learn more about modifying data in your database, refer to Write Transactions.

const CreatePersonInput = () => {
const [name, setName] = useState('');
const realm = useRealm();
const handleAddPerson = () => {
realm.write(() => {
realm.create('Person', {_id: PERSON_ID, name: name, age: 25});
});
};
return (
<>
<TextInput value={name} onChangeText={setName} />
<Button
onPress={() => handleAddPerson()}
title='Add Person'
/>
</>
);
};

Returns

  • Realm Returns a database instance from the RealmProvider context.

Type signature
useObject<T>(type, sdks-open-synced-database-offlineKey): T & Realm.Object<T> | null

The useObject() Hook returns a Realm Object for a given primary key. You can pass an object class or the class name as a string and the primary key.

The useObject() Hook returns null if the object doesn't exist or you have deleted it. The Hook will automatically subscribe to updates and rerender the component using the Hook on any change to the object.

const TaskItem = ({_id}: {_id: number}) => {
const myTask = useObject(Task, _id);
return (
<View>
{myTask ? (
<Text>
{myTask.name} is a task with the priority of: {myTask.priority}
</Text>
) : null}
</View>
);
};

Parameters

  • type: string A string that matches your object model's class name or a reference to a class that extends Realm.Object.

  • primaryKey: T[keyof T] The primary key of the desired object.

Returns

  • Realm.Object | null A Realm Object or null if no object is found.

Type signature
useQuery<T>(type, query?, deps?): Realm.Results<T & Realm.Object<T>>

The useQuery() Hook returns a result that is a collection of Realm Objects of a given type. These are the results of your query. A query can be an object class or the class name as a string.

The useQuery() method subscribes to updates to any objects in the collection and rerenders the component using it on any change to the results.

You can use .filtered() and .sorted() to filter and sort your query results. Do this in the query argument of useQuery so that they only run when there are changes in the dependency array. For more examples, refer to the Read Objects page.

const TaskList = () => {
const [priority, setPriority] = useState(4);
// filter for tasks with a high priority
const highPriorityTasks = useQuery(
Task,
tasks => {
return tasks.filtered('priority >= $0', priority);
},
[priority],
);
// filter for tasks that have just-started or short-running progress
const lowProgressTasks = useQuery(Task, tasks => {
return tasks.filtered(
'$0 <= progressMinutes && progressMinutes < $1',
1,
10,
);
});
return (
<>
<Text>Your high priority tasks:</Text>
{highPriorityTasks.map(taskItem => {
return <Text>{taskItem.name}</Text>;
})}
<Text>Your tasks without much progress:</Text>
{lowProgressTasks.map(taskItem => {
return <Text>{taskItem.name}</Text>;
})}
</>
);
};

Parameters

  • type: string A string that matches your object model's class name or a reference to a class that extends Realm.Object.

  • query?: QueryCallback<T> A query function that can filter and sort query results. Builds on useCallback to memoize the query function.

  • deps?: DependencyList A list of query function dependencies that's used to memoize the query function.

Returns

  • Realm.Results<T> A Realm Object or null if no object is found.

Type signature
useUser<FunctionsFactoryType, CustomDataType, UserProfileDataType>(): Realm.User<FunctionsFactoryType, CustomDataType, UserProfileDataType>

The useUser() Hook provides access to the logged-in user. For example, you can use useUser() to log the current user out.

When changes to the user object happen, this Hook will rerender its parent component. For example, if you call user.refreshCustomData to get updated custom user data, the useUser() parent component will rerender.

function UserInformation() {
const user = useUser();
const {logOut} = useAuth();
const performLogout = () => {
logOut();
};
// Add UI for logging out...
}

Returns

  • Realm.User An instance of the currently-authenticated Atlas user.

Type signature
useApp<FunctionsFactoryType, CustomDataType>(): Realm.App<FunctionsFactoryType, CustomDataType>

Example

The useApp() Hook provides access to a Realm.App instance.

import React from 'react';
import {useApp} from '@realm/react';
function MyApp() {
const app = useApp();
// Proceed to app logic...
}

Returns

  • Realm.App An instance of the current Realm.App created by AppProvider.

Type signature
useAuth(): UseAuth

You destructure the useAuth() Hook result into a result and authentication method.

Type signature
result: AuthResult

Result of authentication Hook operation. For example, result.operation gives you the name of the current operation.

Enum values

  • state: Can be "not-started", "pending", "success", "error".

  • operation: For a list of all operation names, refer to the API documentation.

  • pending: Can be true or false.

  • success: Can be true or false.

  • error: Error-based object or undefined.

The authentication method specifies how you want users to login to your app. useAuth has an authentication method for every App Services authentication provider.

Operation
Parameter
Example
logIn
credentials: An Atlas credential supplied by any supported Atlas App Services authentication provider.

Logs in a user with any authentication mechanism supported by Atlas App Services. If called when a user is logged in, the current user switches to the new user. Usually, it's better to use the more specific login methods.

const {logIn, result} = useAuth();
useEffect(() => logIn(Realm.Credentials.anonymous()), []);
if(result.pending) {
return (<LoadingSpinner/>)
}
if(result.error) {
return (<ErrorComponent/>)
}
if(result.success) {
return (<SuccessComponent/>)
}
//...
logInWithAnonymous
None

Log in with the anonymous authentication provider.

const {logInWithAnonymous, result} = useAuth();
const performLogin = () => {
logInWithAnonymous();
};
logInWithApiKey
key: A string that is linked to an App Services user.

Log in with an API key.

const {logInWithApiKey, result} = useAuth();
const performLogin = () => {
const key = getApiKey();
// user defined function
logInWithApiKey(key);
};
logInWithEmailPassword
credentials: An object with email and password fields.

Log in with Email/Password.

const {logInWithEmailPassword, result} = useAuth();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const performLogin = () => {
logInWithEmailPassword({email, password});
};
logInWithJWT
credentials: A string representation of a user's JWT.

Log in with a JSON Web Token (JWT).

const {logInWithJWT, result} = useAuth();
const performLogin = () => {
const token = authorizeWithCustomerProvider();
// user defined function
logInWithJWT(token);
};
logInWithGoogle
credentials: An object with an idToken or authCode field that should contain the string token you get from Google Identity Services.

Log in with Google.

const {logInWithGoogle, result} = useAuth();
const performLogin = () => {
const token = getGoogleToken();
// user defined function
logInWithGoogle({idToken: token});
};
logInWithApple
idToken: A string you get from the Apple SDK.

Log in with Apple.

const {logInWithApple, result} = useAuth();
const performLogin = () => {
const token = getAppleToken();
// user defined function
logInWithApple(token);
};
logInWithFacebook
accessToken: A string you get from the Facebook SDK.

Log in with Facebook.

const {logInWithFacebook, result} = useAuth();
const performLogin = () => {
const token = getFacebookToken();
// user defined function
logInWithFacebook(token);
};
logInWithFunction
payload: An object that contains user information you want to pass to the App Services function that processes log in requests.

Log in with a custom function.

const {logInWithFunction, result} = useAuth();
const performLogin = () => {
const customPayload = getAuthParams();
// user defined arguments
logInWithFunction(customPayload);
};
logOut
None

Logs out the current user.

const {logOut, result} = useEmailPasswordAuth();
const performLogout = () => {
logOut();
}

You destructure the useEmailPasswordAuth() Hook result into a result and authentication operation.

Type signature
result: AuthResult

Result of operation. For example, result.operation gives you the name of the current operation.

Enum values

  • state: Can be "not-started", "pending", "success", "error".

  • operation: For a list of all operation names, refer to the API documentation.

  • pending: Can be true or false.

  • success: Can be true or false.

  • error: Error-based object or undefined.

useEmailPasswordAuth has a number of operations to facilitate email and password user authentication.

Operation
Parameter
Example
logIn
credentials: An object that contains email and password properties.

Logs a user in using an email and password. You could also call logIn(Realm.Credentials.emailPassword(email, password)). Returns a Realm.User instance of the logged-in user.

const {logIn, result} = useEmailPasswordAuth();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const performLogin = () => {
logIn({email, password});
};
if(result.pending) {
return (<LoadingSpinner/>)
}
if(result.error) {
return (<ErrorComponent/>)
}
if(result.success) {
return (<SuccessComponent/>)
}
//...
logOut
None

Logs out the current user.

const {logOut, result} = useEmailPasswordAuth();
const performLogout = () => {
logOut();
}
register
args: An object that contains email and password properties.

Registers a new user. Requires a user email and password.

const {register, result} = useEmailPasswordAuth();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const performRegister = () => {
register({email, password});
};
confirm
args: An object that contains token and tokenId properties.

Confirms a user account. Requires a token and tokenId.

const {confirm, result} = useEmailPasswordAuth();
const performConfirmation = () => {
confirm({token, tokenId});
};
resendConfirmationEmail
args: An object that contains an email property.

Resends a confirmation email.

const {resendConfirmationEmail, result} = useEmailPasswordAuth();
const [email, setEmail] = useState('');
const performResendConfirmationEmail = () => {
resendConfirmationEmail({email});
};
retryCustomConfirmation
args: An object that contains an email property.

Retries confirmation with a custom function.

const {retryCustomConfirmation, result} = useEmailPasswordAuth();
const [email, setEmail] = useState('');
const performRetryCustomConfirmation = () => {
retryCustomConfirmation({email});
};
sendResetPasswordEmail
args: An object that contains an email property.

Sends a password reset email.

const {sendResetPasswordEmail, result} = useEmailPasswordAuth();
const [email, setEmail] = useState('');
const performSendResetPasswordEmail = () => {
sendResetPasswordEmail({email});
};
resetPassword
args: An object that contains token, tokenId, and password properties.

Resets a user's password.

const {resetPassword, result} = useEmailPasswordAuth();
const [password, setPassword] = useState('');
const performResetPassword = () => {
resetPassword({token, tokenId, password});
};
callResetPasswordFunction

args: An object that contains email and password properties.

restArgs: Additional arguments that you need to pass to your custom reset password function.

Calls your App Services backend password reset function. Can pass arguments to the function as needed.

const {callResetPasswordFunction, result} = useEmailPasswordAuth();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const performResetPassword = () => {
callResetPasswordFunction({email, password}, "extraArg1", "extraArg2");
};
Type signature
createRealmContext(realmConfig?): RealmContext

Use createRealmContext() to configure more than one database. The createRealmContext() method creates a React Context object for a database with a given Configuration. The Context object contains the following:

  • A Context Provider component that wraps around child components and provides them with access to Hooks.

  • Various prebuilt Hooks that access the configured database.

To work with more than one database, you need to destructure a new provider and its associated Hooks from the result of createRealmContext(). You can call this new database provider and use its associated Hooks the same way you would with the RealmProvider imported from the @realm/react library. Namespace your providers to avoid confusion about which provider and Hooks you're working with.

Parameters

Returns

  • RealmContext An object containing a RealmProvider component, and the useRealm, useQuery and useObject Hooks.

For a detailed guide, refer to Expose More Than One Database.

← 
 →