使用 React 调用 Apollo GraphQL 服务器
欢迎在推特上关注我,我很乐意接受您对话题或改进方面的建议。/克里斯
本文是 GraphQL 系列文章的一部分。
- 使用 Node.js 和 Express 构建 GraphQL 服务器
- 使用 Node.js 和 Apollo 框架构建 GraphQL 服务器
- 我们正在使用 React 调用 Apollo GraphQL 服务器。
本文将介绍如何从前端与 Apollo GraphQL 服务器进行交互。如果您还不熟悉如何创建 Apollo 服务器,请先阅读这篇文章:创建 Apollo 服务器
本文将探讨以下内容:
- 设置时,我们需要指定服务器的 URL 并实例化一个客户端。
- 查询,我们可以使用查询组件来查询数据。
- 变异,我们可以使用变异组件来执行变异操作。
- 轮询/显式 获取,Apollo 在轮询、显式获取和数据获取方面提供了一些不错的功能。
设置
要使用 GraphQL 设置 React 应用,我们需要一些库。`GraphQL`apollo-boost提供了我们需要实例化的对象,并提供了一个高阶Provider ,我们需要用它来包装我们的应用。首先,请进行必要的安装:react-apolloapollo-boostApolloClientURLreact-apolloApolloProvider
yarn add react-apollo apollo-boost graphql
安装完成后,我们就可以进行设置了。请前往index.js并输入以下内容:
import React, { Component } from "react";
import ApolloClient from "apollo-boost";
import { ApolloProvider } from "react-apollo";
import Local from “./components/Local”;
const localGraphQL = "http://localhost:4000/graphql";
const client = new ApolloClient({
uri: localGraphQL
});
class App extends Component {
render() {
return (
<ApolloProvider client={client}>
<div>
<h2>My first Apollo app </h2>
</div>
</ApolloProvider>
);
}
}
export default App;
上面我们首先实例化ApolloClient它,并在过程中为其提供urlGraphQL 服务器的位置。
其次,我们将整个应用程序封装在我们的实例中ApolloProvider,并且我们还client使用我们的实例设置了它的属性ApolloClient。
现在我们已准备好与 GraphQL 服务器进行交互。
询问
要查询 Apollo 服务器,我们需要做三件事:
- 请填写我们的
gql查询 - 利用
react-apollo库提供的查询组件 - 渲染响应
要编写gql查询,我们需要先导入相关库graphql-tag,然后编写 GraphQL 查询,如下所示:
const getRates = gql`
{
rates(currency: “USD”) {
currency
rate
}
}`;
接下来,我们需要Query从 [此处应填写来源名称] 导入该组件react-apollo,并将其作为输入属性提供我们刚刚定义的查询语句,如下所示:
const Data = () => (
<Query query={getRates} >
// render the query results
</Query>
);
在组件的第一个子组件中,Query我们调用了一个以对象作为参数的函数。该对象具有以下属性:
- 正在加载,只要我们的查询还没有完成,这就是
true - 如果查询返回错误,则表示出现错误。
- 数据,即我们查询得到的数据结果。
现在我们已经了解了这些属性以及如何使用它们,让我们把所有内容整合起来:
import React from "react";
import { Query } from "react-apollo";
import gql from "graphql-tag";
const getRates = gql`
{
products(type: "DVD") {
name
price
}
}`;
const Data = () => (
<Query query={getRates} >
{({ loading, error, data }) => {
if (loading) return <p>Loading…</p>;
if (error) return <p>Error :(</p>;
return data.products.map(({ name, price }) => (
<div key={name}>
<p>{`${name}: ${price}`}</p>
</div>
));
}}
</Query>
);
export default Data;
我们现在已经学会了如何从 GraphQL 服务器读取数据并将其呈现给用户。
轮询
你不仅需要获取数据,有时还需要定期获取数据,而无需显式导航到特定页面或按下特定按钮来触发 GET 请求。例如,我们在聊天应用程序中使用此功能来实现实时性。我们这里所说的轮询,就是按照我们指定的固定时间间隔获取数据。Query我们学习使用的组件内置了轮询功能,我们只需要设置一个pollInterval属性来指定两次数据获取之间的时间间隔(以毫秒为单位)。让我们来看看具体示例:
import React from "react";
import { Query } from "react-apollo";
import gql from "graphql-tag";
const GET_DATA = gql`
{
products {
name
id
}
}
`;
const DataPull = () => (
<Query query={GET_DATA} pollInterval={500}>
{(loading, error, data, startPolling, stopPolling) => {
if (loading) return null;
if (error) return `Error!: ${error}`;
return (
<React.Fragment>
{data.products.map(p => <div>{p.name}</div>)}
<button onClick={()=> startPolling()}>Start polling</button>
<button onClick={() => stopPolling()}>Stop polling</button>
</React.Fragment>;
)
}}
</Query>
);
export default DataPull;
以上我们介绍了以下新概念:
- pollInterval参数用于指定轮询间隔,单位为毫秒。如您所见,我们将其设置为
500例如半秒。 - startPolling函数允许我们在之前停止轮询后重新启动轮询。
- stopPolling函数允许我们随时停止轮询。
重新获取
有时我们会遇到需要显式获取数据以确保查看最新数据的情况。这样做的目的是为了响应用户操作,而不是轮询。让我们来看看如何使用此refetch功能:
import React from "react";
import { Query } from "react-apollo";
import gql from "graphql-tag";
const GET_DATA = gql`
{
products {
name
id
}
}
`;
const Refetch = () => (
<Query query={GET_DATA}>
{(loading, error, data, refetch) => {
if (loading) return null;
if (error) return `Error!: ${error}`;
return (
<React.Fragment>
<div>
{data.prop}
<button onClick={() => refetch()}>Fetch</button>
</div>
</React.Fragment>
)
}}
</Query>
);
export default Refetch;
refetch上面我们可以看到,我们给Query子函数添加了另一个参数,如下所示:
{(loading, error, data, refetch) => {
}}
这个refetch参数是一个我们可以调用的函数,因此我们可以像这样把它连接到标记中的一个按钮:
<button onClick={() => refetch()}>Fetch</button>
突变
当我们对 GraphQL 服务器执行 mutation 操作时,需要执行以下操作:
-
调用正确的突变
-
使用来自 Mutation 组件
react-apollo
以上内容听起来似乎没什么特别的,实际上也确实如此。那么,让我们从第一件事开始,也就是我们的变更查询:
我们将使用库gql中的辅助函数graphql-tag来创建 mutation 查询。之后,我们使用关键字 `mutation` mutation,然后给 mutation 命名并指定其输入参数$person。此时,我们的查询如下:
const ADD_PERSON = gql`
mutation AddPerson($person: Person!) {
}
`;
现在我们可以调用addPerson在 GraphQL 服务器中定义的实际 mutation 了。你的 mutation 查询现在应该如下所示:
const ADD_PERSON = gql`
mutation AddPerson($person: Person!) {
addPerson(person: $person) {
id
}
}
`;
接下来,我们将通过与 React 组件配合使用来应用 mutation 查询Mutation。该组件需要两样东西:
- 填充属性信息
mutation, - 定义组件的子组件时
Mutation,我们需要为其提供一个函数,该函数的第一个参数包含mutation触发变更发生的函数,第二个参数则是一个包含以下属性的对象data:errorloading
让我们从组件的初始使用部分开始Mutation,并设置其mutation属性,如下所示:
import React from "react";
import { Mutation } from "react-apollo";
import gql from "graphql-tag";
const ADD_PERSON = gql`
mutation AddPerson($person: Person!) {
addPerson(person: $person) {
id
}
}
`;
<Mutation mutation={ADD_PERSON}>
</Mutation>
上面我们已经使用了Mutation组件,并mutation通过变更查询设置了属性ADD_PERSON。接下来是定义Mutation组件的子组件。正如我们之前提到的,子组件是一个函数,如下所示:
(addPerson, { data, loading, error }) => (
// JSX
)
上述函数预期返回 JSX 代码。我们需要定义一段 JSX 代码,以便使用以下功能:
- addPerson(),此函数将执行变更查询。
- 加载中,这个布尔值将告诉我们变更是否正在进行中,使用此值来决定是否使用加载指示器。
- 数据,这是你的变更查询完成后返回的数据。
现在我们了解了函数参数的用途,接下来让我们定义 JSX 代码。通常,我们需要定义一个表单来收集数据,所以我们来这样做:
<form onSubmit={e => {
e.preventDefault();
addPerson({ variables: { person: { name: input.value } } });
input.value = “”;
}} >
<input ref={node => { input = node; }} />
<button type=”submit”>Add Person</button>
{loading &&
<div>adding person…</div>
}
{ data &&
<div>response data</div>
}
{ error &&
<div>Error adding person…</div>
}
</form>
如上图所示,我们有一个表单、一个输入字段和一个可点击的按钮。我们将该addPerson()方法连接到onSubmit()表单。请注意,我们也解决了如何将数据传递给变更查询的问题。我们给该addPerson()方法提供一个对象,该对象有一个属性,variables我们将该属性赋值给一个对象person。该person属性与变更查询中的输入参数相同。
其他字段用作条件 JSX data,如果它们的值为真,loading则error选择显示它们。
就是这样,调用带有某些参数的 mutation 并显示响应(无论是实际数据还是错误)就是这么简单。
以下是全部代码。
import React from "react";
import { Mutation } from "react-apollo";
import gql from "graphql-tag";
const ADD_PERSON = gql`
mutation AddPerson($person: Person!) {
addPerson(person: $person) {
id
}
}
`;
const DataInput = () => {
let input;
return (
<Mutation mutation={ADD_PERSON}>
{(addPerson, { data, loading, error }) => (
<div>
<form onSubmit={e => {
e.preventDefault();
addPerson({ variables: { person: { name: input.value } } });
input.value = “”;
}} >
<input ref={node => { input = node; }} />
<button type=”submit”>Add Person</button>
{loading &&
<div>adding person…</div>
}
{ data &&
<div>response data</div>
}
{ error &&
<div>Error adding person…</div>
}
</form>
</div>
)}
</Mutation>)
}
export default DataInput;
概括
我们研究了从后端与数据交互的不同方法。
-
获取数据时,如果我们使用该
Query组件,可以通过向其query属性填充gql问题来获取数据。 -
轮询数据
pollInterval:如果我们在组件上设置了该属性,Query就可以轮询我们的 GraphQL 后端。 -
通过使用额外的参数,我们可以显式地获取
refetch数据,以便在需要时进行显式获取。 -
通过触发突变,我们了解到我们可以利用该
Mutation组件来执行突变。
