您将要创建的内容
在这些教程中,我将向您展示如何使用aws AppSync 和 react Native 创建 graphql 数据库并与之交互。这个应用程序将具有实时和离线功能,这是我们通过 AppSync 开箱即用的功能。
在这篇文章中,我们将通过构建 React Native 客户端来完成这一切。该项目有点过于复杂,无法逐步引导您,但我将解释项目架构并向您展示源代码的关键部分。
应用架构和文件夹结构概述
我们的应用程序将有一个主入口点,该入口点将由两个选项卡式视图组成。一个选项卡将列出我们 GraphQL 数据库中的城市,另一个选项卡将是添加新城市的输入表单。Cities选项卡将是一个导航器,允许用户导航到各个城市。
我们将主要组件存储在源文件夹中,并在src目录中拥有其他文件夹来保存我们的 GraphQL 突变、查询和订阅。
我们还将有一个资产文件夹来保存我们的图像。
创建和配置 React Native 客户端
作为参考,请查看 教程 GitHub 存储库中此应用程序的最终代码,但我将概述我从头开始创建应用程序所采取的一些步骤。
首先,我们使用Expo创建了一个新的 React Native 应用程序 。
在新创建的项目中,我们安装了我们的依赖项。对于 GraphQL 和 AppSync 功能,我们使用了以下依赖项:
aws-appsync aws-appsync-react graphql-tag react-apollo uuid
我们还在 UI 设计中使用了以下依赖项:
react-navigation react-native-elements react-native-vector-icons
此外,一旦安装了 Vector Icons 库,我们将其链接:
react-native link react-native vector-icons
安装依赖项后,我们从 AppSync 控制台下载了 AppSync.js 文件。在我们的 AppSync 项目控制台中,我们在底部选择了 React Native ,然后单击橙色的下载按钮下载此配置文件。
此配置文件包含我们创建新客户端所需的 AppSync 客户端信息。
配置提供者和存储
应用程序的顶层是我们将在其中进行配置以将 AppSync api与 React Native 客户端连接起来。 如果你之前使用过redux或 React Apollo,这一切都会很熟悉。如果您还没有,请记住 a 的任何子级Provider
,在我们的例子中是ApolloProvider
,都可以访问其给定的功能。
以下代码是我们新建的 App.js 文件,它是从我们的index.js入口点导入的主要组件。
import React from 'react' import Tabs from './src/Tabs' import AWSAppSyncClient from "aws-appsync"; import { Rehydrated } from 'aws-appsync-react'; import { ApolloProvider } from 'react-apollo'; import appSyncConfig from './aws-exports'; const client = new AWSAppSyncClient({ url: appSyncConfig.graphqlEndpoint, region: appSyncConfig.region, auth: { type: appSyncConfig.authType, apiKey: appSyncConfig.apiKey, } }); const WithProvider = () => ( <ApolloProvider client={client}> <Rehydrated> <Tabs /> </Rehydrated> </ApolloProvider> ); export default WithProvider
AWSAppSyncClient
在此文件中,我们将结合使用构造函数 fromaws-appsync
以及aws- exports.js 文件中的配置来设置新的 AppSync 客户端,该文件提供 GraphQL API URL、区域、身份验证类型和身份验证 API 密钥。
然后,我们将主入口点(将保存我们的选项卡导航的Tabs.js文件)包装在 an ApolloProvider
中,并将 AppSync 客户端作为客户端属性传入。我们还将组件包装在Tabs
我们Rehydrated
从中导入的组件中aws-appsync-react
。这将确保我们已经从异步存储中读取并在渲染 UI 之前重新水化了我们的缓存。
现在我们的应用程序将能够从我们的 AppSync 端点查询数据,还可以执行突变和订阅!
导航
该应用程序的主要入口点是一个选项卡式导航,在 Tabs.js 文件中使用 React Navigation 实现。
我们在这里所做的是TabNavigator
使用两个选项卡创建和导出 a。这些是:
Cities:这个组件列出了我们的城市,它本身就是一个导航器组件。这个组件是一个导航器,因为我们希望能够导航到每个单独的城市并查看城市内的位置。
AddCity:这个组件是我们能够添加新城市的表单。
可重用组件
这个应用程序只有一个可重用的组件,一个自定义的TextInput
. 由于我们将一遍又一遍地复制这种风格和功能,我们决定将其作为自己的组件。输入组件在 Input.js中实现。
城市列表和城市导航
该应用程序的主视图是我们将从 GraphQL 检索的城市列表。我们希望能够从每个列出的城市导航到该城市的详细视图,我们可以在其中添加位置。
为此,我们将Cities.js 设为自己的 StackNavigator,并将City.js 设为我们在选择城市时导航到的组件。当点击 中的城市时Cities
,我们将其名称和 id 作为道具传递给City
.
城市.js
在这个组件中,我们使用查询fetchlistCities
,并且我们还订阅 NewCitySubscription
,因此当添加新城市时,即使是来自另一个客户端,我们也将处理该订阅并更新我们的城市数组。该 listCities
查询使我们的组件中可用的城市数组为this.props.cities
.
城市.js
在这个组件中,我们通过一个城市作为导航的道具(可用)。我们使用 city值通过查询获取所选城市的位置列表 。我们订阅新位置的方式与我们在Cities.js中订阅新城市的方式类似,使用 订阅。我们还提供 添加新城市时的 功能。 props.navigation.state.params.city
id
listLocations
NewLocationSubscription
optimisticResponse
update
添加城市
最后,我们需要在 AddCity.js 文件中实现向 GraphQL API 添加新城市的功能。为此,我们将一个突变与一个将调用的表单连接起来 createCity
,传递表单输入的值。
AddCity 有一个onAdd
我们在 GraphQL com位置中定义的函数,它不仅将一个新城市写入我们的 GraphQL 数据库,而且还使用optimisticResponse
和的组合实现了一个乐观的 UI update
。
突变、查询和订阅
突变、查询和订阅是与我们的 GraphQL API 集成的核心功能。在我们的应用程序中,此功能使用 AppSync 客户端在Cities.js、City.js和AddCity.js文件中实现。
让我们仔细看看突变、查询和订阅是如何在我们的代码中实现的。
查询
首先,让我们看看如何创建和导出可以与 AppSync Schema 中的 listCities 查询交互的GraphQL查询。此代码包含在src/queries/ListCities.js文件中。
import gql from 'graphql-tag'; export default gql` query listCities { listCities { items { name country id } } }`
接下来,我们在Cities.js文件中导入此查询,以及一些帮助程序 from ,并使用 和 react-apollo
连接我们希望访问此数据的组件 from 。compose
graphql
react-apollo
import { compose, graphql } from 'react-apollo' import ListCities from './queries/ListCities' class Cities extends React.Component { // class definition here // now have access to this.props.cities } export default compose( graphql(ListCities, { props: props => ({ cities: props.data.listCities ? props.data.listCities.items : [], }) }) )(CityList)
现在我们可以从我们的 GraphQL 服务器作为 props 访问城市数组。我们可以 this.props.cities
用来映射来自 GraphQL 的城市数组。
突变
要创建一个突变,首先我们需要创建一个基本的 GraphQL 突变并将其导出。我们在 src/mutations/CreateCity.js 文件中执行此操作。
import gql from 'graphql-tag' export default gql` mutation addCity($name: String!, $country: String!, $id: ID!) { createCity(input: { name: $name, country: $country, id: $id }) { name country id } } `
现在我们可以在AddCity.js文件中导入这个突变(连同 Apollo 助手) 并在组件中使用它:
import { compose, graphql } from 'react-apollo' import AddCityMutation from './mutations/AddCity' class AddCity extends React.Component { // class definition here // now have access to this.props.onAdd() } export default compose( graphql(AddCityMutation, { props: props => ({ onAdd: city => props.mutate({ variables: city }) }) }) )(AddCity)
现在,我们可以访问一个名为 的道具 onAdd
,我们将一个我们想要发送给突变的对象传递给它!
订阅
订阅允许我们订阅数据更改并让它们在我们的应用程序中实时更新。如果我们要通过添加或删除一个城市来更改我们的数据库,我们希望我们的应用程序能够实时更新。
首先,我们需要创建突变并将其导出,以便我们可以在客户端中访问它。我们将其保存在 src/subscriptionsNewCitySubscriptions.js 文件中。
import gql from 'graphql-tag' export default gql` subscription NewCitySub { onCreateCity { name country id } }`;
现在我们可以在 Cities.js中导入并附加订阅。我们已经研究了如何从我们的 API 中获取城市。现在让我们更新此功能以订阅新更改并在添加新城市时更新城市数组。
import AllCity from './queries/AllCity' import NewCitiesSubscription from './subscriptions/NewCitySubscription'; import { compose, graphql } from 'react-apollo' class Cities extends React.Component { componentWillMount(){ this.props.subscribeToNewCities(); } render() { // rest of component here } } export default compose( graphql(ListCities, { options: { fetchPolicy: 'cache-and-network' }, props: (props) => { return { cities: props.data.listCities ? props.data.listCities.items : [], subscribeToNewCities: params => { props.data.subscribeToMore({ document: NewCitiesSubscription, updateQuery: (prev, { subscriptionData: { data : { onCreateCity } } }) => { return { ...prev, listCities: { __typename: 'CityConnection', items: [onCreateCity, ...prev.listCities.items.filter(city => city.id !== onCreateCity.id)] } } } }) } } } }) )(Cities)
我们添加了一个名为 的新道具 subscribeToNewCities
, 我们将其称为componentDidMount
。在订阅中,我们传入一个文档(订阅定义)并 updateQuery
描述我们希望在更新时发生什么。
我们从传递给函数的道具中解构 createCity
(包含突变) updateQuery
,并返回所有现有值以及 listCities
包含先前城市的更新数组以及我们从中获得的新城市数据 createCity
。
乐观的用户界面
如果我们不想等待订阅从我们的 API 返回最新数据以更新我们的 UI,该怎么办?
import { compose, graphql } from 'react-apollo' import AddCityMutation from './mutations/AddCity' class AddCity extends React.Component { // class definition here // now have access to this.props.onAdd() } export default compose( graphql(AddCityMutation, { props: props => ({ onAdd: city => props.mutate({ variables: city, optimisticResponse: { __typename: 'Mutation', createCity: { ...city, __typename: 'City' } }, update: (proxy, { data: { createCity } }) => { const data = proxy.readQuery({ query: ListCities }); data.listCities.items.unshift(createCity); proxy.writeQuery({ query: ListCities, data }); } }) }) }) )(AddCity)
在这里,我们向 mutate 函数参数对象添加了两个新属性:
optimisticResponse
定义您希望在更新功能中可用的新响应。update
接受两个参数,代理(它允许你从缓存中读取)和你想用来进行更新的数据。我们读取当前的缓存proxy.readQuery
(
结论
GraphQL 正变得越来越主流。围绕 GraphQL 的许多复杂性与管理后端和 API 层有关。然而,像 AppSync 这样的工具将这种复杂性抽象化,让开发人员无需花费大部分时间来配置和处理服务器。
- 城市.js
- 城市.js
- 查询
- 突变
- 订阅
- 乐观的用户界面