Docs 菜单
Docs 主页
/ /
Atlas App Services

教程:React Native 的 Atlas Device Sync

在此页面上

  • 先决条件
  • 从模板应用开始
  • 设置模板应用程序
  • 安装依赖项
  • 构建应用程序
  • 测试应用程序
  • 了解模板应用
  • Atlas App Services 应用
  • React 原生应用程序
  • 添加优先级字段
  • 定义优先级
  • 更新 Item 数据模型
  • 添加优先级选取器
  • 运行并测试应用
  • 更新同步订阅
  • 向用户界面添加模式切换
  • 更新同步订阅
  • 测试应用程序
  • 接下来的步骤

预计完成时间: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 文档中的设置开发环境

  • 本教程从“模板应用程序”开始。创建“模板应用程序”需要 Atlas 帐号、API 密钥和 App Services CLI。

    • 如需了解有关创建 Atlas 帐户的更多信息,请参阅 Atlas 入门文档。在本教程中,您需要一个带有免费层级集群的 Atlas 帐户。

    • 您还需要一个用于登录的 MongoDB Cloud 账户的 Atlas API 密钥。您必须是项目所有者才能使用 App Services CLI 创建模板应用。

    • 要了解有关安装 App Services CLI 的更多信息,请参阅安装 App Services CLI 。安装后,使用 Atlas 项目的 API 密钥运行登录命令。

本教程基于名为 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 模板应用。

使用以下步骤在计算机上启动并运行模板应用:

1

在终端中,转到包含客户端代码的目录。如果使用 App Services CLI 创建了应用程序,请转到 MyTutorialApp/react-native.todo.flex。否则,请转到已下载或复制项目的根目录。然后运行以下命令以安装应用程序依赖项:

npm install

要在iOS设备或模拟器上构建并运行应用,请使用 CocoaPods 安装其他iOS依赖项。

cd ios
npx pod-install
2

此时,您应该拥有一个功能齐全的 React Native 应用,它可以在 iOS、Android 或两者上运行。

如果您遇到错误或其他问题,请确保您的 React Native 环境设置正确。请参阅 React Native 官方开发环境设置指南。请遵循适用于您的开发操作系统和目标操作系统的所有步骤。

为了确保一切在 iOS 上正常运行,请构建应用并在 iOS 模拟器中运行:

npm run ios

为确保一切都能在 Android 上运行,请执行以下操作:

  1. 启动 Android 模拟器。有关如何执行此操作的详细信息,请参阅在 Android 模拟器上运行应用程序

  2. 在模拟器上构建应用程序:

    npm run android

    一个常见的错误是 Error: spawn ./gradlew EACCES。这意味着项目文件权限没有达到要求。在 MacOS 上,您可以通过在终端中输入 chmod 755 android/gradlew 来解决此问题。

3

构建完成后,您应该拥有一个在模拟器上运行的功能齐全的应用。在该应用中,注册一个新帐户并测试功能:

  • 将一些待办事项添加到列表中。

  • 按下一个或两个列项的复选框,将其标记为已完成。

  • 按下项目上的 X 可将其从列表中删除。

  • 在应用程序中切换网络连接,模拟离线模式。

如果你连接到 Atlas 集群并查询 todo.Item 集合,你可以看到应用的数据。只要 React Native 应用不处于离线模式,应用中的新数据和更改就会自动同步到 todo.Item 集合。

提示

要学习;了解如何连接到Atlas集群,请参阅连接到集群。

同样,集合中的任何更改都会自动同步到 React Native 应用。尝试更改集群中事项的完成状态 — 只要网络连接可用,React Native 应用就会自动更新为新值。

提示

要了解有关更新集群中数据的更多信息,请参阅更新文档

现在您已经让模板应用运行起来了,让我们深入到代码中,看看具体执行情况。

模板应用在 backend 目录中包含一个全面配置的 App Services App。它在 atlasConfig.json 中具有唯一的 appId 值,客户端应用程序使用该值进行连接。

它还包括以下预定义配置:

  • 链接到 Atlas 集群的数据源。

  • todo.Item 集合的一个数据模型,与 React Native 应用中的 Item 类匹配。

  • 身份验证提供程序,允许用户使用电子邮箱和密码注册并登录您的应用。

  • 具有单个会话角色的灵活同步配置,允许用户读取和写入自己的事项并查看其他用户的事项。

该 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 属性。这将使我们能够根据待办事项的重要性来组织待办事项,并允许我们只关注最重要的事项。

1

我们希望允许使用少量命名的优先级别,我们还希望能够轻松地对级别进行排序。为此,我们将使用辅助函数来定义 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]。这意味着优先级高(意味着更重要)则索引值低。

2

现在我们拥有 enum,它可以定义 priority 字段的可能值。但是,我们仍然需要在 Item 类中定义 priority 字段。

source/ItemSchema.tsx 中添加以下几行代码,以便在 Item 数据模型中添加 priority

source/ItemSchema.tsx
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
},
},
};
}

注意

为什么没有中断同步

此时,您的 React Native Item 模型及其在 App Services App 中的相应模式不再一致。没关系!

向 Realm 对象添加属性不是一项重大更改,因此不需要重置客户端。模板应用启用了开发模式,因此对客户端 Realm 对象的更改会反映在服务器端模式中。有关更多信息,请参阅开发模式更新数据模型

3

现在,您的应用的数据模型针对每个 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() 处理程序

source/CreateToDoPrompt.tsx
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

source/ItemListView.tsx
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()

source/ItemListView.tsx
<CreateToDoPrompt
onSubmit={({summary, priority}) => {
setShowNewItemOverlay(false);
createItem({summary, priority});
}}
/>

最后,修改列表项模板,以在 summary 之前显示待办事项的 priority

source/ItemListView.tsx
<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>
4

您的应用现在应该允许用户为新的待办事项设置优先级。

重新生成应用并将其打开。添加一些新的待办事项以确认您可以选择优先级,并且清单显示每个待办事项的优先级。

Device Sync 协议使用灵活的模型,其中每个同步客户端都使用标准 RQL 查询来选择应用程序数据的子集,然后订阅该子集。这会自动将子集中所有数据的最新版本拉取到设备,并在设备之间同步数据变更。

例如,您正在使用的模板应用对当前用户拥有的事项具有以下内置订阅:

source/ItemListView.tsx
realm.subscriptions.update(mutableSubs => {
mutableSubs.removeByName(itemSubscriptionName);
mutableSubs.add(
realm.objects(Item).filtered(`owner_id == "${user?.id}"`),
{name: ownItemsSubscriptionName},
);
});

可以在运行时自定义订阅,只同步应用需要的数据。让我们添加一个功能来演示如何操作。

在本教程中,我们将添加一个按钮,用于在两种模式之间切换:一种模式是应用程序同步所有待办事项,另一种模式是仅同步 priority 为 High(高)或 Severe(极高)的重要待办事项。

1

首先,向 ItemListView 组件添加一个 useState() 挂钩以跟踪当前模式:

ItemListView.tsx
const [showImportantOnly, setShowImportantOnly] = useState(false);

然后在待办事项列表底部的 <ListItem> 后添加一个新按钮,用于切换模式:

source/ItemListView.tsx
<Button
title={showImportantOnly ? 'Show All' : 'Show Important Only'}
buttonStyle={{
...styles.addToDoButton,
backgroundColor: showImportantOnly ? '#00A35C' : '#FFC010',
}}
onPress={() => setShowImportantOnly(showImportantOnly => !showImportantOnly)}
/>
2

此时,应用可以在用户界面中切换模式,但我们还没有做任何其他事情,因此这些模式在功能上完全相同。让我们更新同步订阅,以便只同步与当前模式相关的数据。

ItemListView 组件的第一个 useEffect 中,添加用来检查当前模式的代码,并在 showImportantOnly 模式处于活动状态时向查询追加一个额外的 priority 筛选器:

source/ItemListView.tsx
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 的第二个参数的依赖项列表中。

3

您的应用现已设置为根据当前模式修改同步订阅。

重新构建并运行应用,以确保一切正常。您应当能够创建、完成和删除待办事项,以及在查看所有事项和仅查看重要事项之间切换。

提示

在启用开发者模式的情况下更改订阅

在本教程中,当您首次更改优先级字段的订阅和查询时,该字段将自动添加到 Device Sync Collection Queryable Fields 中。出现这种情况是因为模板应用默认启用了开发模式。如果未启用开发模式,您必须手动将该字段添加为可查询字段,以便在客户端同步查询中使用它。

有关更多信息,请参阅可查询字段

注意

分享反馈

怎么样?使用页面右下角的 Rate this page 小组件来评价其有效性。如果有任何问题,也可以在 Github 存储库 上提交问题。

来年

什么是 Atlas App Services?