使用Apollo Client开始GraphQL
这篇文章是YAMAP工程师Advent Calender 2021第5天的文章。
关于这篇文章
我写了这篇文章,目的是为了共享在前端GraphQL引入过程中学到的知识和备忘录。
在这篇文章中,我们总结了使用Apollo Client将GraphQL引入到React应用程序的具体方法。
“Apollo Client是什么”
简单来说,这是一个很棒的库,用于在Web前端环境中处理GraphQL(主要为React,并通过集成支持其他框架)。它还具备缓存机制和状态管理机制,并具有现代化且非常易于理解的接口。
Apollo Client是一个全面的JavaScript状态管理库,可以帮助你通过GraphQL管理本地和远程数据。使用它可以获取、缓存和修改应用程序数据,同时自动更新UI。
安装
假设您已经建立好了 Next.js 应用程序,我们接下来将继续进行。
下方是 Nextjs 的介绍。
开发环境
我只需要中文的一个版本,以下是预期的开发环境。
-
- エディタ
VSCode
言語
JavaScript または TypeScript
フレームワーク
Nextjs
React
安装图书馆
首先,安装与 Apollo Client 相关的库。
$ yarn add @apollo/client graphql
$ yarn add -D apollo
安装编辑器扩展功能
安装 VSCode 上的 Apollo GraphQL 扩展程序。
通过这个方法,将根据后面介绍的 GraphQL Schema,在编辑器上实现查询代码补全的功能(这将大大提高开发效率,毫无疑问地)。
创建Apollo的设置文件
接下来,在项目根目录中创建 apollo.cofig.js 文件。
module.exports = {
client: {
includes: ['./src/**/*.js'],
service: {
name: 'yamap-app',
url: 'https://api.yamap.com/graphql',
},
},
};
在 client.service.url 中,我们写下了 GraphQL API 的终结点。
顺便提一下,还有一个叫Apollo Studio的服务,据说使用它可以变得幸福。如果正在使用它,只需指定已注册服务中图表的名称即可。
module.exports = {
client: {
includes: ['./src/**/*.js'],
service: 'my-graph-in-apollo-studio'
},
};
下载模式
使用事先安装好的 Apollo 包,下载模式。
$ yarn apollo service:download -c ./apollo.config.js graphql-schema.json
我认为 `graphql-schema.json` 文件是在项目根目录中生成的。这将使得编辑器(VSCode)上的代码补全功能能够生效。
实施
我将使用Apollo Client实际获取用户列表数据。
ApolloClient 的实现方式
我们要使用包含在 @apollo/client 中的 ApolloClient 类。
import { ApolloClient, InMemoryCache } from "@apollo/client";
const client = new ApolloClient({
uri: "https://api.yamap.com/graphql",
cache: new InMemoryCache({}),
});
export default client;
将ApolloProvider集成进来。
如果你使用Next.js应用程序,需要在pages文件夹下创建_app.js文件,并实现自定义应用程序。
import { ApolloProvider } from "@apollo/client";
import client from "../apollo-client"; // さっき作った apolloClient を import
function CustomApp({ Component, pageProps }) {
return (
<ApolloProvider client={client}>
<Component {...pageProps} />
</ApolloProvider>
);
}
export default CustomApp;
获取数据(企业社会责任)
首先,使用 useFetch() 在客户端获取数据。
查询
import { gql } from "@apollo/client"
export const GET_USERS_QUERY = gql`
query ListUsers($first: Int!, $after: String) {
users(first: $first, after: $after) {
pageInfo {
endCursor
hasNextPage
hasPreviousPage
startCursor
}
edges {
cursor
node {
id
databaseId
nickname
}
}
}
}
`
客户端获取
import { useQuery } from "@apollo/client"
import { GET_USERS_QUERY } from "../users-query"
function Users () {
const { data, loading, error } = useQuery(QUERY, {
variables: {
first: 10,
}
});
const users = data?.users.edges.map(edge => edge.node);
if (loading) {
return <div>Loading...</div>
}
if (error) {
console.error(error);
return null;
}
return (
<div>
<h1>ユーザー一覧</h1>
<div>
{users?.map(user => (
<div key={user.id}>
{user.nickname}
</div>
))}
</div>
</div>
)
}
export default Users;
获取数据(服务器渲染)
查询将重用之前提到的GET_USERS_QUERY。
服务器端获取
function Users ({ initialData, initialError }) {
const { data, loading, error } = useQuery(QUERY, {
variables: {
ssr: false, // getServerSideProps によって、既にサーバーサイドでデータ取得済のため
first: 10,
}
});
if (!initialData && loading) {
return <div>Loading...</div>
}
if (initialError || error) {
console.error(error);
return null;
}
const users = data?.users.edges.map(edge => edge.node) || initialData?.users.edges.map(edge => edge.node);
return (
<div>
<h1>ユーザー一覧</h1>
<div>
{users?.map(user => (
<div key={user.id}>
{user.nickname}
</div>
))}
</div>
</div>
)
}
export async function getServerSideProps() {
const { data, error } = await client.query({
query: QUERY,
variables: {
first: 10,
}
});
return {
props: {
initialData: data,
initialError: error,
},
};
这就是全部了。
如果不考虑分页功能,SSR 的代码可能会更简单一些。
希望我的建议对你有所帮助。