使用Graphcool、React和Apollo来实现GraphQL的查询和变更
首先
虽然这篇文章的部分内容与之前的有重复,但我希望能够详细说明如何使用Graphcool在使用create-react-app创建的React应用程序中实现GraphQL的Query和Mutation,而不需要再解释Graphcool本身。
在这个应用程序中,我们要求创建以下类型的屏幕,能够简单地列出文章信息并保存新的投稿。
(由于这只是为了体验GraphQL的功能而创建的,所以没有进行太多细致的错误处理或针对产品的优化…)
完成的形象 de
执行环境
-
- Mac OS Sierra: v10.12.6
-
- node: v8.2.0
- npm: v5.3.0
事前准备
安装create-react-app
npm install -g create-react-app
安装Graphcool(Graphcool的命令行界面)
npm install -g graphcool
使用 Graphcool 登录(本地环境的认证)
如果尚未创建Graphcool账户,则请从官方网站上注册并创建一个账户,然后执行以下命令。
graphcool login
成功登录后,将在主目录下自动生成.graphcoolrc文件。
创建并确认React应用程序的启动
# ホームディレクトリに移動
cd ~/
# `react-graphcool-sample`ディレクトリを作成し、Reactアプリの土台を作る
create-react-app react-graphcool-sample
# react-graphcool-sampleのルートに移動
cd react-graphcool-sample/
# Reactアプリの起動を確認
yarn start
建立Graphcool环境
确认能够启动React应用后,打开另一个终端,并进入react-graphcool-sample的根目录,使用graphcool init命令在名为server(也可以是任意名称)的目录内创建用于使用Graphcool的文件。
cd ~/react-graphcool-sample/
graphcool init server
主要创建了以下三个要点。
-
- graphcool.yml ( Graphcoolを利用するための設定ファイル。作成した型定義ファイルやserverless functionの参照、パーミッションの指定など)
-
- types.graphql (GraphQLのスキーマ定義ファイル)
- src/(serverless functionが格納されたディレクトリ)
types.graphql(模式定义)
我們將編輯types.graphql文件,添加下面的型別定義Post。(將原先的User型別等註釋掉,只保留Post的型別)
type Post @model {
id: ID! @isUnique
title: String!
content: String
}
在type中声明类型,并在每个字段的冒号后面使用ID或String指示这些字段的类型。
!指定它们为Not Null。
有关这些类型和模式的详细信息,请参阅GraphQL官方网页。
此外,带有@的被称为指令(Directive),用于对字段进行特殊设置(在上述示例中,将值存储在id字段中并确保唯一性)。更详细的信息,请参考官方的指令章节。
graphcool.yml(指定权限等)
这次不使用无服务器函数,只保留下面的内容,其他的都注释掉。
types: ./types.graphql
permissions:
- operation: "*"
请提供以下内容的中文本地化释义,仅需一种选项:
/源代码
删除 react-graphcool-sample/server/src 下的 src 文件夹。
发布Graphcool
进入由graphcool init创建的目录,并执行graphcool deploy命令,将上述配置部署到Graphcool的服务上。
每当有对模式等的更改时,都需要执行相同的命令来应用更改。
# serverディレクトリに移動
cd server
graphcool deploy
执行graphcool deploy命令时会询问以下三个问题:
在第一个问题中,会要求您指定Shared Clusters(免费云托管服务)的选择,请选择其中的某个地区。
如果没有特别要求,您可以按下Enter键继续使用默认选项。
? Please choose the cluster you want to deploy to (Use arrow keys)
Shared Clusters:
❯ shared-eu-west-1
shared-ap-northeast-1
shared-us-west-2
接下来,会问您目标名称,如果没有特别要求,只需按下回车键,默认将应用prod 的设置。
? Please choose the target name (prod)
接下来,会问到服务名称,但默认情况下将应用目录名。
? Please choose the service name (server)
成功部署后,你可以从云控制台上确认相应的项目。
确认用的URL是在https://console.graph.cool/后面,指定由graphcool init创建的目录名。
在上述示例中,它将变为https://console.graph.cool/server/。
(访问控制台之前,你需要先登录Graphcool)
您可以通过此控制台添加数据、确认终端节点并删除项目等。
另外,如果部署成功,graphcool init 会在创建的目录内生成如下所示的连接到Graphcool的设置文件。
targets:
prod: shared-eu-west-1/xxxxxxxxxxxxxxxxxxxxxxxx
default: prod
xxxxxxxxxxxxxxxxxxxxxxxx的部分是指项目ID,下次执行graphcool deploy时,将基于这些信息去连接到Graphcool服务。(项目ID也可以在控制台上确认)
获取端点
在部署完成时显示的消息末尾,我们会使用Simple API的值来设置后续连接React应用程序的API配置,所以请保留一份备份。
(即使忘记了,您可以在server文件夹中运行graphcool info命令,就可以确认以下的端点)
$ graphcool info
Service Name Cluster / Service ID
────────────── ────────────────────────────────────────────
server shared-eu-west-1/xxx
API: Endpoint:
────────────── ────────────────────────────────────────────────────────────
Simple API: https://api.graph.cool/simple/v1/xxxxx
Relay API: https://api.graph.cool/relay/v1/xxxxx
Subscriptions API: wss://subscriptions.graph.cool/v1/xxxxx
阿波罗的内置连接设置。
安装Apollo客户端库,该库是用于连接GraphQL API的。然后将其集成到React应用程序中,并进行API连接设置。
阿波罗安装
我们来安装以下四个软件包。
yarn add apollo-client-preset react-apollo graphql-tag graphql
在安装完包后,为了使React应用程序能够使用,将下面的描述添加到src/index.js的开头。
import { ApolloProvider } from "react-apollo";
import { ApolloClient } from "apollo-client";
import { HttpLink, InMemoryCache } from "apollo-client-preset";
API连接设置
接下来,我们将通过以下代码生成一个带有API连接信息的ApolloClient实例。将GRAPHQL_ENDPOINT替换为之前保存的Simple API的值。
const GRAPHQL_ENDPOINT = ""; // Simple APIの値を代入
if (!GRAPHQL_ENDPOINT) {
throw Error("GRAPHQL_ENDPOINTが設定されていません。");
}
const client = new ApolloClient({
link: new HttpLink({
uri: GRAPHQL_ENDPOINT
}),
cache: new InMemoryCache()
});
将上述实例传递给的Props,然后将AppComponent包装在ApolloApp组件中进行最终渲染。
const ApolloApp = (
<ApolloProvider client={client}>
<App />
</ApolloProvider>
);
ReactDOM.render(ApolloApp, document.getElementById("root"));
registerServiceWorker();
创建React组件
我們創建了一個用於列出和發布新聞信息的UI組件。
在src文件夹的根目录下创建一个components文件夹,并将Component文件存放在其中。
(将App组件也移动到components文件夹中)
以下是该段文本的中文翻译:
├ public
├ server
└ src
└ components
├ App.js:渲染PostList和PostForm组件
├ Post.js:渲染单个文章的信息(标题和内容)
├ PostList.js:通过查询获取所有文章,并使用渲染每篇文章的信息
└ PostForm.js:通过变更添加保存新文章的信息
发布(文章信息显示)
为了进行Props的类型检查,需要安装prop-types库。
yarn add -D prop-types
import React, { Component } from "react";
import PropTypes from "prop-types";
class Post extends Component {
render() {
return (
<dl>
<dt>{this.props.post.title}</dt>
<dd>{this.props.post.content}</dd>
</dl>
);
}
}
Post.propTypes = {
post: PropTypes.shape({
id: PropTypes.string,
title: PropTypes.string,
content: PropTypes.string
})
};
export default Post;
帖子列表(获取和列出文章信息)
为了从GraphQL获取所有文章数据,我们将编写以下查询语句。
query {
allPosts {
id
title
content
}
}
您可以通过在浏览器的控制台中访问或者在通过graphcool init创建的目录中运行graphcool playground命令来打开Playground,并试用此查询的执行结果。
如果您想了解更多关于查询API的信息,例如指定文章ID来获取单个文章的详细信息,请参考此处。
gql是react-apollo的辅助函数,用于解析字符串并执行GraphQL操作。
import React, { Component, Fragment } from "react";
import Post from "./Post";
import gql from "graphql-tag";
import { graphql } from "react-apollo";
const ALL_POSTS_QUERY = gql`
query {
allPosts {
id
title
content
}
}
`;
class PostList extends Component {
render() {
if (this.props.allPostsQuery && this.props.allPostsQuery.loading) {
return <p>データを読み込み中</p>;
}
if (this.props.allPostsQuery && this.props.allPostsQuery.error) {
return <p>エラーが発生しました。</p>;
}
const allPosts = this.props.allPostsQuery.allPosts;
if (allPosts.length === 0) {
return <p>投稿がありません。</p>;
}
return (
<Fragment>
{allPosts.map(post => <Post key={post.id} post={post} />)}
</Fragment>
);
}
}
export default graphql(ALL_POSTS_QUERY, { name: "allPostsQuery" })(PostList);
graphql函数(react-apollo的辅助函数)接受解析后的查询(ALL_POSTS_QUERY)作为第一个参数,传递一个指定存储从GraphQL API获取的数据的Props名称(allPostsQuery)的对象作为第二个参数,并接受一个组件作为参数,返回一个扩展了的组件的函数(高阶组件)。
简而言之,将 graphql(ALL_POSTS_QUERY, { name: “allPostsQuery” }) 作为 HoC,将 PostList 作为参数传入,并最终导出扩展后的 PostList。
此外,由于ApolloProvider对根组件App进行了包装,因此App的子组件PostList可以通过Props(props.allPostsQuery)获取从GraphQL API获取的数据。
props.allPostsQuery中含有以JSON格式存储的获取结果数据。
从开始获取数据到完成的过程中,loading的值为true,如果获取数据失败,则error的值为Error对象,因此在render()的开始部分处理这些情况的处理。
文章添加表单.js (PostForm.js)
在PostList中,使用查询(query)来检索数据的处理已经编写完毕,现在是时候使用变更(mutation)来编写数据写入操作了。
您需要将从输入表单中获取的数据作为变量传递给GraphQL API。您可以通过在变量声明前加上“$”符号来将变量传递给mutation的参数。
此外,传递给mutation参数的变量将被传递给createPost的参数,当createPost执行(写入数据)完成后,将返回id。
mutation createPostMutation($title: String!, $content: String) {
createPost(title: $title, content: $content) {
id
}
}
为了将值存储到mutation的变量中,我们将创建一个用于文章投稿的输入表单。
我们将提供两个输入框,一个用于标题,另一个用于输入内容的用户界面,并分别在