教程:React Native 的 Atlas Device Sync
在此页面上
预计完成时间:30 分钟,具体取决于您在使用 React Native 方面的经验
您可以使用RealmReact Native SDK 和 @ 域/React React Native使用 构建移动应用程序。本教程将引导您了解如何构建自己的使用Flexible Sync的应用。
在本教程中,我们将从预构建 TypeScript 模板应用程序开始,了解如何将所有内容组合在一起。
该应用是一个预构建模板,包括有效的 React Native 应用程序(前端)及其相应的 App Services App 配置文件(后端)。
模板应用是一个基本的待办事项清单应用程序,允许用户执行各种操作来管理任务:
创建电子邮箱/密码帐户并登录和退出应用程序。
创建、读取、更新和删除自己的任务。
查看所有任务,即使用户不是所有者。
模板应用正常运行后,您将向现有 Item
模型添加一个新的 priority
字段,并更新灵活同步订阅以仅显示优先级范围内的项目。该示例说明如何根据自己的需要调整模板应用。考虑到模板应用的当前结构,您不一定会进行此项更改。
模板应用程序提供一个切换开关,用于模拟处于“离线模式”的设备。此切换开关可以让您快速测试 Device Sync 功能,模拟没有互联网连接的用户。但是,您可能会在生产应用程序中删除此切换开关。
注意
查看“快速入门”
如果更喜欢自己探索,而不是跟随指导教程,请查看 React Native 快速入门。它包括可复制的代码示例以及使用 Atlas Device Sync 设置 React Native 应用程序所需的基本信息。
先决条件
在开始本教程之前,必须为 React Native 开发设置好本地环境。有关详细说明,请参阅 React Native 文档中的设置开发环境。
从模板应用开始
本教程基于名为 react-native.todo.flex
的 React Native SDK 灵活同步模板应用。我们从默认应用开始,然后在其上构建新功能。
要了解有关模板应用的更多信息,请参阅模板应用。
如果您还没有 Atlas 帐号,请注册以部署“模板应用程序”。
按照“创建App Services App”指南中描述的步骤操作,然后选择 Create App from Template 。 选择Real-time Sync模板。 这将创建一个预先配置为与Device Sync模板应用客户端之一一起使用的App Services App 。
创建模板应用后,用户界面会显示一个标有 Get the Front-end Code for your Template 的模态窗口。此模态窗口提供有关将模板应用客户端代码下载为 .zip
文件或使用 App Services CLI 获取客户端的说明。
选择 .zip
或 App Services CLI 方法后,请按照屏幕上的说明获取客户端代码。对于本教程,请选择 JavaScript (React Native) 客户端代码。
注意
默认的Windows ZIP 实用程序可能会显示 .zip 文件为空。 如果遇到这种情况,请使用可用的第三方 zip 程序。
appservices apps create 命令设置后端,并创建一个 React Native 模板应用,供您用作本教程的基础。
在终端窗口中运行以下命令,创建一个名为“MyTutorialApp”的应用,将该应用部署在 US-VA
地区,并将其环境设置为“开发”(而不是生产或 QA)。
appservices app create \ --name MyTutorialApp \ --template react-native.todo.flex \ --deployment-model global \ --environment development
该命令在当前路径中创建一个新目录,其名称与 --name
标志的值相同。
Github您可以创建分支并克隆包含Device Sync 客户端代码的 存储库。React Native客户端代码位于 https://github.com/mongodb/template-app-react-native-todo。
如果您使用此过程来获取客户端代码,则必须创建一个模板应用以配合客户端使用。按照创建模板应用中的说明操作,使用 Atlas App Services 用户界面、App Services CLI 或 Admin API 创建 Device Sync 模板应用。
设置模板应用程序
使用以下步骤在计算机上启动并运行模板应用:
安装依赖项
在终端中,转到包含客户端代码的目录。如果使用 App Services CLI 创建了应用程序,请转到 MyTutorialApp/react-native.todo.flex
。否则,请转到已下载或复制项目的根目录。然后运行以下命令以安装应用程序依赖项:
npm install
要在iOS设备或模拟器上构建并运行应用,请使用 CocoaPods 安装其他iOS依赖项。
cd ios npx pod-install
构建应用程序
此时,您应该拥有一个功能齐全的 React Native 应用,它可以在 iOS、Android 或两者上运行。
如果您遇到错误或其他问题,请确保您的 React Native 环境设置正确。请参阅 React Native 官方开发环境设置指南。请遵循适用于您的开发操作系统和目标操作系统的所有步骤。
为了确保一切在 iOS 上正常运行,请构建应用并在 iOS 模拟器中运行:
npm run ios
为确保一切都能在 Android 上运行,请执行以下操作:
启动 Android 模拟器。有关如何执行此操作的详细信息,请参阅在 Android 模拟器上运行应用程序。
在模拟器上构建应用程序:
npm run android 一个常见的错误是
Error: spawn ./gradlew EACCES
。这意味着项目文件权限没有达到要求。在 MacOS 上,您可以通过在终端中输入chmod 755 android/gradlew
来解决此问题。
测试应用程序
构建完成后,您应该拥有一个在模拟器上运行的功能齐全的应用。在该应用中,注册一个新帐户并测试功能:
将一些待办事项添加到列表中。
按下一个或两个列项的复选框,将其标记为已完成。
按下项目上的 X 可将其从列表中删除。
在应用程序中切换网络连接,模拟离线模式。
如果你连接到 Atlas 集群并查询 todo.Item
集合,你可以看到应用的数据。只要 React Native 应用不处于离线模式,应用中的新数据和更改就会自动同步到 todo.Item
集合。
提示
要学习;了解如何连接到Atlas集群,请参阅连接到集群。
同样,集合中的任何更改都会自动同步到 React Native 应用。尝试更改集群中事项的完成状态 — 只要网络连接可用,React Native 应用就会自动更新为新值。
提示
要了解有关更新集群中数据的更多信息,请参阅更新文档。
了解模板应用
现在您已经让模板应用运行起来了,让我们深入到代码中,看看具体执行情况。
Atlas App Services 应用
模板应用在 backend
目录中包含一个全面配置的 App Services App。它在 atlasConfig.json
中具有唯一的 appId
值,客户端应用程序使用该值进行连接。
它还包括以下预定义配置:
链接到 Atlas 集群的数据源。
todo.Item
集合的一个数据模型,与 React Native 应用中的Item
类匹配。身份验证提供程序,允许用户使用电子邮箱和密码注册并登录您的应用。
具有单个会话角色的灵活同步配置,允许用户读取和写入自己的事项并查看其他用户的事项。
React 原生应用程序
该 React Native 应用是一个配置全面的移动客户端,可在 iOS 和 Android 设备上运行。
该应用程序使用 @realm/react 库。该库包括 React 钩子和组件,可简化 Atlas 后端和 Realm 数据库的工作。
该应用包含一些配置文件和目录,除非您想自定义该应用,否则可以忽略这些文件和目录。对于本教程,您应该熟悉 source/
目录中的 React 组件:
文件名 | 说明 |
---|---|
ItemSchema.tsx | Item 类,包括对象数据模型。我们在 AppWrapper.tsx 中导入此类,将其包含在应用程序的整体 Realm 模式中。 |
AppWrapper.tsx | 这是应用的根组件。它充当包装器组件并包含所有 @realm/react 提供程序。在这里,您可以配置您的领域以及与 Atlas 后端的连接。 |
App.tsx | 应用的大部分功能都包含在该组件及其子组件中。由于 @realm/react 提供程序包裹在该组件周围,因此它可以访问 Atlas 后端的实例、用户对象,并与 Realm 数据库交互。 |
WelcomeView.tsx | 用户首次打开应用时看到的用户注册和登录表单。 |
ItemListView.tsx | 用户登录后与之交互的主要待办事项列表应用程序。它查询 Item Realm 对象并将这些对象显示在列表中。它还包括用于创建新的 Item 对象并将其存储在 Realm 中的代码。 |
CreateToDoPrompt.tsx | 一个允许我们为新 Item 对象输入数据的 UI 表单。实际创建新对象的代码位于 ItemListView.tsx 中。 |
LogoutButton.tsx | 一个可重用的按钮,用于注销已通过身份验证的用户。 |
OfflineModeButton.tsx | 模拟离线模式的可重用按钮,可以暂停和恢复当前 Realm syncSession 。 |
添加优先级字段
现在,你对模板应用中已提供的内容更加熟悉了,让我们编写一些代码来实现新功能。
在本教程中,我们将向 Item
对象添加一个新的 priority
属性。这将使我们能够根据待办事项的重要性来组织待办事项,并允许我们只关注最重要的事项。
定义优先级
我们希望允许使用少量命名的优先级别,我们还希望能够轻松地对级别进行排序。为此,我们将使用辅助函数来定义 enum
对象,该对象将一组有序级别名称与代表其优先级的整数进行互相映射。
在 source/ItemSchema.tsx
中的 import 语句下直接添加以下代码:
function createEnum(arr) { arr.forEach((p, i) => arr[p] = i); return arr; } // Priority.High === 1 // Priority[Priority.High] === "High" export const Priority = createEnum([ "Severe", "High", "Medium", "Low", ])
enum
中的优先级按从最重要到最不重要排序。每个级别对应的索引值从最重要的 Priority[0]
增加到最不重要的 Priority[3]
。这意味着优先级高(意味着更重要)则索引值低。
更新Item
数据模型
现在我们拥有 enum
,它可以定义 priority
字段的可能值。但是,我们仍然需要在 Item
类中定义 priority
字段。
在 source/ItemSchema.tsx
中添加以下几行代码,以便在 Item
数据模型中添加 priority
:
export class Item extends Realm.Object<Item> { _id!: BSON.ObjectId; isComplete!: boolean; summary!: string; owner_id!: string; priority!: string; static schema: Realm.ObjectSchema = { name: 'Item', primaryKey: '_id', properties: { // This allows us to automatically generate a unique _id for each Item _id: {type: 'objectId', default: () => new BSON.ObjectId()}, // All todo items will default to incomplete isComplete: {type: 'bool', default: false}, summary: 'string', owner_id: 'string', priority: { // Store the index value of the Priority enum rather than the name type: 'int', default: Priority.High }, }, }; }
添加优先级选取器
现在,您的应用的数据模型针对每个 Item
对象,包含一个 priority
。让我们更新应用用户界面,以便您在向列表添加新待办事项时可以选择优先级值。
首先,我们将安装一个外部库来实现优先级选取器组件。在终端中进入项目根目录并运行以下命令:
npm install @react-native-picker/picker
如果为 iOS 构建,请确保在安装软件包后链接相关的 Cocoapods:
npx pod-install
提示
可能需要在安装后重新构建您的应用。为此,请停止项目的捆绑程序,然后运行构建命令:
npm run ios
npm run android
现在软件包已经完全安装完毕,让我们更新新的待办事项创建提示组件以使用选取器。
将以下导入添加到 source/CreateToDoPrompt.tsx
的顶部:
import {Picker} from '@react-native-picker/picker'; import {Priority} from './ItemSchema';
然后,修改 CreateToDoPrompt
组件:
将
priority
添加到onSubmit()
属性定义中使用状态挂钩跟踪
priority
将状态连接到您导入的
Picker
组件将
priority
传递给onSubmit()
处理程序
type Props = { onSubmit(args: {summary: string; priority: string;}): void; }; export function CreateToDoPrompt(props: Props): React.ReactElement<Props> { const {onSubmit} = props; const [summary, setSummary] = useState(''); const [priority, setPriority] = useState(Priority.High); return ( <View style={styles.modalWrapper}> <Text h4 style={styles.addItemTitle}> Add To-Do Item </Text> <Input placeholder="What do you want to do?" onChangeText={(text: string) => setSummary(text)} autoCompleteType={undefined} /> <Picker style={{width: '80%'}} selectedValue={priority} onValueChange={value => setPriority(value)}> {Priority.map(priority => ( <Picker.Item key={priority} label={priority} value={Priority[priority]} /> ))} </Picker> <Button title="Save" buttonStyle={styles.saveButton} onPress={() => onSubmit({summary, priority})} /> </View> ); }
在 source/ItemListView.tsx
中,修改 createItem()
函数,接受并使用 priority
:
const createItem = useCallback( ({summary, priority}: {summary: string, priority: string}) => { realm.write(() => { return new Item(realm, { summary, owner_id: user?.id, priority }); }); }, [realm, user], );
然后,修改创建待办事项提交处理程序以接受 priority
级别并将其传递给 createItem()
:
<CreateToDoPrompt onSubmit={({summary, priority}) => { setShowNewItemOverlay(false); createItem({summary, priority}); }} />
最后,修改列表项模板,以在 summary
之前显示待办事项的 priority
:
<ListItem key={`${item._id}`} bottomDivider topDivider hasTVPreferredFocus={undefined} tvParallaxProperties={undefined}> <Text>{item.priority}</Text> <ListItem.Title style={styles.itemTitle}> {item.summary} </ListItem.Title> <ListItem.Subtitle style={styles.itemSubtitle}> {item.owner_id === user?.id ? '(mine)' : ''} </ListItem.Subtitle> <ListItem.CheckBox checked={item.isComplete} checkedColor={COLORS.primary} iconType="material" checkedIcon="check-box" uncheckedIcon="check-box-outline-blank" onPress={() => toggleItemIsComplete(item._id)} /> <Button type="clear" onPress={() => deleteItem(item._id)} icon={ <Icon type="material" name="clear" size={12} color="#979797" tvParallaxProperties={undefined} /> } /> </ListItem>
更新同步订阅
Device Sync 协议使用灵活的模型,其中每个同步客户端都使用标准 RQL 查询来选择应用程序数据的子集,然后订阅该子集。这会自动将子集中所有数据的最新版本拉取到设备,并在设备之间同步数据变更。
例如,您正在使用的模板应用对当前用户拥有的事项具有以下内置订阅:
realm.subscriptions.update(mutableSubs => { mutableSubs.removeByName(itemSubscriptionName); mutableSubs.add( realm.objects(Item).filtered(`owner_id == "${user?.id}"`), {name: ownItemsSubscriptionName}, ); });
可以在运行时自定义订阅,只同步应用需要的数据。让我们添加一个功能来演示如何操作。
在本教程中,我们将添加一个按钮,用于在两种模式之间切换:一种模式是应用程序同步所有待办事项,另一种模式是仅同步 priority
为 High(高)或 Severe(极高)的重要待办事项。
向用户界面添加模式切换
首先,向 ItemListView
组件添加一个 useState()
挂钩以跟踪当前模式:
const [showImportantOnly, setShowImportantOnly] = useState(false);
然后在待办事项列表底部的 <ListItem>
后添加一个新按钮,用于切换模式:
<Button title={showImportantOnly ? 'Show All' : 'Show Important Only'} buttonStyle={{ ...styles.addToDoButton, backgroundColor: showImportantOnly ? '#00A35C' : '#FFC010', }} onPress={() => setShowImportantOnly(showImportantOnly => !showImportantOnly)} />
更新同步订阅
此时,应用可以在用户界面中切换模式,但我们还没有做任何其他事情,因此这些模式在功能上完全相同。让我们更新同步订阅,以便只同步与当前模式相关的数据。
在 ItemListView
组件的第一个 useEffect
中,添加用来检查当前模式的代码,并在 showImportantOnly
模式处于活动状态时向查询追加一个额外的 priority
筛选器:
useEffect(() => { if (showAllItems) { realm.subscriptions.update(mutableSubs => { mutableSubs.removeByName(ownItemsSubscriptionName); mutableSubs.add(realm.objects(Item), {name: itemSubscriptionName}); }); } else if (showImportantOnly) { realm.subscriptions.update(mutableSubs => { mutableSubs.removeByName(itemSubscriptionName); mutableSubs.add( realm.objects(Item).filtered(`owner_id == "${user?.id}" && priority <= 1`), {name: ownItemsSubscriptionName}, ); }); } else { realm.subscriptions.update(mutableSubs => { mutableSubs.removeByName(itemSubscriptionName); mutableSubs.add( realm.objects(Item).filtered(`owner_id == "${user?.id}"`), {name: ownItemsSubscriptionName}, ); }); } }, [realm, user, showAllItems, showImportantOnly]);
重要
还应将 showImportantOnly
添加到 useEffect
的第二个参数的依赖项列表中。
测试应用程序
您的应用现已设置为根据当前模式修改同步订阅。
重新构建并运行应用,以确保一切正常。您应当能够创建、完成和删除待办事项,以及在查看所有事项和仅查看重要事项之间切换。
提示
在启用开发者模式的情况下更改订阅
在本教程中,当您首次更改优先级字段的订阅和查询时,该字段将自动添加到 Device Sync Collection Queryable Fields 中。出现这种情况是因为模板应用默认启用了开发模式。如果未启用开发模式,您必须手动将该字段添加为可查询字段,以便在客户端同步查询中使用它。
有关更多信息,请参阅可查询字段。
接下来的步骤
请阅读我们的 React Native SDK 文档。
在 MongoDB 开发者中心查找面向开发者的博客文章和集成教程。
加入 MongoDB Community 论坛,向其他 MongoDB 开发者和技术专家学习。
利用触发器和 Atlas Search 为模板应用添加功能。
探索工程和专家团队提供的示例项目。