Docs 菜单

Docs 主页Atlas App Services

教程:Atlas Device Sync for React Native

在此页面上

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

预计完成时间: 30分钟,具体取决于您使用 React Native 的经验

您可以使用 Realm React Native SDK 和 @realm/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 密钥和应用服务来创建模板应用。

    • 您可以在Atlas 入门文档中了解有关创建 Atlas 帐户的更多信息。对于本教程,您需要一个具有免费层级集群的 Atlas 帐户。

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

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

本教程基于名为 react-native.todo.flex 的 React Native SDK 灵活同步模板应用。我们从默认应用开始,然后在其上构建新功能。

要了解有关模板应用的更多信息,请参阅模板应用

如果您还没有 Atlas 帐户,请注册以部署模板应用。

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

1

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

npm install

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

cd ios
npx pod-install
2

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

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

3

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

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

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

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

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

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

提示

要了解如何连接到 Atlas 集群,请参阅连接到数据库部署。

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

提示

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

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

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

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

  • 链接到 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

提示

可能需要在安装后重新构建您的应用。为此,请停止项目的捆绑程序,然后运行构建命令:

现在软件包已经完全安装完毕,让我们更新新的待办事项创建提示组件以使用选取器。

将以下导入添加到 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

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

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

注意

分享反馈

怎么样?使用页面右下角的 Share Feedback(分享反馈)选项卡,告诉我们本教程是否有帮助或者您是否有任何问题。

← 教程:Atlas Device Sync for Kotlin