使用Graphcool、React和Apollo来实现GraphQL的查询和变更

首先

虽然这篇文章的部分内容与之前的有重复,但我希望能够详细说明如何使用Graphcool在使用create-react-app创建的React应用程序中实现GraphQL的Query和Mutation,而不需要再解释Graphcool本身。

在这个应用程序中,我们要求创建以下类型的屏幕,能够简单地列出文章信息并保存新的投稿。
(由于这只是为了体验GraphQL的功能而创建的,所以没有进行太多细致的错误处理或针对产品的优化…)

完成的形象 de

スクリーンショット-2018-03-26-2.38.44.png

执行环境

    • 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,并试用此查询的执行结果。

スクリーンショット 2018-03-26 2.29.04.png

如果您想了解更多关于查询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的变量中,我们将创建一个用于文章投稿的输入表单。
我们将提供两个输入框,一个用于标题,另一个用于输入内容的用户界面,并分别在

标签内使用

广告
将在 10 秒后关闭
bannerAds