A todo list (task manager) app showcasing how to create, read, update, and delete data while offline using MongoDB's Atlas Device SDK for React Native (fka Realm).
TIP: This app can be run together with the corresponding Electron example app using the same App Services App.
The following shows the project structure and the most relevant files.
To learn more about the backend file structure, see App Configuration.
├── backend - App Services App
│ └── (see link above)
│
├── frontend - React Native App
│ ├── app
│ │ ├── components
│ │ │ ├── AddTaskForm.tsx - Creates a task
│ │ │ ├── OfflineModeButton.tsx - Pauses/resumes the sync session
│ │ │ ├── TaskItem.tsx - Updates or deletes a task
│ │ │ └── TaskList.tsx - Displays all tasks
│ │ │
│ │ ├── hooks
│ │ │ ├── useSyncConnection.ts - Functions for re/disconnecting
│ │ │ └── useTaskManager.ts - Functions for managing (CRUD) tasks
│ │ │
│ │ ├── models
│ │ │ ├── index.ts - Exports all (1) models
│ │ │ └── Task.ts - Data model
│ │ │
│ │ ├── screens
│ │ │ ├── LoginScreen.tsx - Login and registration
│ │ │ ├── TaskScreen.tsx - Display task components
│ │ │ └── TaskScreenSync.tsx - Task screen with sync-related ops
│ │ │
│ │ ├── AppNonSync.tsx - Local-only app and opens Realm
│ │ └── AppSync.tsx - Sync-enabled app and opens Realm
│ │
│ ├── index.js - Entry point
│ └── package.json - Dependencies
│
├── README.md - Instructions and info
└── sync.config.js - Option to use Device Sync enabled app
This app focuses on showing how to work with data no matter the network connection.
It specifically addresses the following points:
- Registering and logging in to an App Services App using Email/Password Authentication.
- Accessing and updating data:
- Create
- Query/Read
- Sort and filter the query
- Update
- Delete
- Using offline/local-first reads and writes.
- Shows configuration for opening a synced Realm.
- Realms are opened immediately without waiting for downloads from the server.
- See Offline Support below.
- Shows configuration for opening a synced Realm.
- Allowing users to only read and write to their own tasks via data access rules/permissions.
- See Set Data Access Permissions further below.
- The app demonstrates both how to use either:
- A) A local-only app (see AppNonSync.tsx).
- B) A Device Sync enabled app (see AppSync.tsx).
- Choose which one to use via sync.config.js.
Users who have logged in at least once will have their credentials cached on the client. Thus, a logged in user who restarts the app will remain logged in. @realm/react's UserProvider
automatically handles this for you by checking if the app.currentUser
already exists.
Data that was previously synced to the device will also exist locally in the Realm database. From this point on, users can be offline and still query and update data. Any changes made offline will be synced automatically to Atlas and any other devices once a network connection is established. If multiple users modify the same data either while online or offline, those conflicts are automatically resolved before being synced.
When opening a Realm, we can specify the behavior in the Realm configuration when opening it for the first time (via newRealmFileBehavior
) and for subsequent ones (via existingRealmFileBehavior
). We can either:
OpenRealmBehaviorType.OpenImmediately
- Opens the Realm file immediately if it exists, otherwise it first creates a new empty Realm file then opens it.
- This lets users use the app with the existing data, while syncing any changes to the device in the background.
OpenRealmBehaviorType.DownloadBeforeOpen
- If there is data to be downloaded, this waits for the data to be fully synced before opening the Realm.
This app opens a Realm via RealmProvider
(see AppSync.tsx) and passes the configuration as props. We use DownloadBeforeOpen
for new Realm files (first-time opens) in order to show a loading indicator (via RealmProvider
's fallback
prop) until the data has been synced. We use OpenImmediately
for existing Realm files in order to use the app while offline if the user has logged in at least once before.
See OpenRealmBehaviorConfiguration for possible configurations of new and existing Realm file behaviors.
- Node.js
- React Native development environment
- Refer to the "React Native CLI Quickstart".
Start by deploying a free Atlas cluster and create an Atlas database.
You can either choose to set up your App via a CLI (this has fewer steps and is much faster since all configurations are already provided in the backend directory), or via the App Services UI (steps provided below).
To import and deploy changes from your local directory to App Services you can use the command line interface:
- Set up Realm CLI.
- In the provided backend directory (the App Services App), update the following:
- Cluster Name
- Update the
"clusterName"
in data_sources/mongodb-atlas/config.json to the name of your cluster. - (The default name is
Cluster0
.)
- Update the
- App ID
- There is no
"app_id"
defined in realm_config.json since we will create a brand new App. If you for some reason are updating an existing app, add an"app_id"
field and its value.
- There is no
- Cluster Name
- Push and deploy the local directory to App Services:
realm-cli push --local <path to backend directory>
- Once pushed, verify that your App shows up in the App Services UI.
- 🥳 You can now go ahead and install dependencies and run the React Native app.
To sync data used in this app you must first:
- Create an App Services App.
- Enable Email/Password Authentication.
- For this example app, we automatically confirm users' emails.
- Enable Flexible Sync with Development Mode enabled.
- When Development Mode is enabled, queryable fields will be added automatically, and schemas will be inferred based on the client Realm data models.
- For information, queryable fields used in this app include:
- Global (all collections):
_id
Task
collection:isComplete
,userId
- Global (all collections):
- (Development Mode should be turned off in production.)
- Don't forget to click
Review Draft and Deploy
.
From the frontend directory, run:
npm install
If developing with iOS, also run:
npx pod-install
- Copy your Atlas App ID from the App Services UI.
- Set
SYNC_CONFIG.enabled
totrue
and paste the copied ID as the value of the existing variableSYNC_CONFIG.appId
in sync.config.js:
import Config from 'react-native-config';
export const SYNC_CONFIG = {
enabled: true,
appId: Config.ATLAS_APP_ID || 'YOUR_APP_ID',
};
- Alternatively you can add a
.env
file to your project with the following contents:This file is included in theATLAS_APP_ID=your_app_id
.gitignore
so that it won't be committed to any code repositories.
- Start Metro (the JavaScript bundler) in its own terminal:
npm start
- In another terminal, start the app:
# Open the app on an iOS simulator.
npm run ios
# Open the app on an Android emulator.
npm run android
To run the app on an actual device, see React Native's Running on Device.
If you set up your App Services App via a CLI, you can skip this step as the permissions should already be defined for you.
After running the client app for the first time, modify the rules for the collection in the App Services UI.
- Collection:
Task
- Permissions:
readOwnWriteOwn
(see corresponding json) - Explanation:
- A user should be able to read and write to their own document (i.e. when
Task.userId === <App User ID>
), but not anyone else's.
- A user should be able to read and write to their own document (i.e. when
- Permissions:
To learn more and see examples of permissions depending on a certain use case, see Device Sync Permissions Guide and Data Access Role Examples.
A great help when troubleshooting is to look at the Application Logs in the App Services UI.
If permission is denied:
- Make sure your IP address is on the IP Access List for your App.
- Make sure you have the correct data access permissions for the collections.
- See Set Data Access Permissions further above.
Removing the local database can be useful for certain errors.
On an iOS simulator:
- Press and hold the app icon on the Home Screen.
- Choose to remove the app and its data.
On an Android emulator via Android Studio:
- Quit the emulator if it is running.
- Open
Device Manager
. - Select
Wipe Data
for the relevant emulator.