紧接上篇react+graphql起手和特性介绍(二),介绍完graphql与koa的服务搭建和graphql的一些常用特性,接下来我们介绍下在react中如何使用graphql
我们使用create-react-app创建react应用:
npm i -g create-react-app
mkdir react-graphql-app
create-react-app react-graphql-app
安装以下前端依赖
npm install react-apollo graphql-tag graphql apollo-client apollo-cache-inmemory apollo-link-http
各个依赖包的作用:
- apollo-link-http 请求配置和网络请求能力
- apollo-cache-inmemory 数据缓存
- apollo-client 请求流程控制,生成请求数据,错误控制,响应数据解析
- graphql-tag 查询类的schema数据解析,包含对应的 webpack-loader
- react-apollo 连接graphql与react
- graphql 提供graphql的核心执行能力
然后我们进行react和graphql的整合
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { ApolloProvider } from 'react-apollo';
import App from './App';
// 我们可以自定义fetch,对请求进行统一处理
const customFetch = (uri, options) => {
return fetch(uri, options);
};
const client = new ApolloClient({
// 连接到graphql服务器
link: createHttpLink({ uri: 'http://localhost:9191/graphql', fetch: customFetch }),
// 设置缓存
cache: new InMemoryCache(),
});
// ApolloProvider 为react提供graphql能力
const WrappedApp = (
);
ReactDOM.render(WrappedApp, document.getElementById('root'));
为了能解析.graphql文件,需要修改webpack配置,添加graphql-loader
// config/webpack.config.dev.js && config/webpack.config.prod.js
...
module.exports = {
...
module: {
strictExportPresence: true,
rules: [
...
{
// 解析 .graphql/.gql 后缀的loader
test: /\.(graphql|gql)$/,
exclude: /node_modules/,
loader: 'graphql-tag/loader',
},
...
]
}
...
}
我们以post为示例,讲一下在组件中要做什么操作
创建定义查询的schema文件
# src/post.graphql
# 导入 user.graphql
#import "./user.graphql"
# fragment 定义片段,可以用于多个地方
fragment PostInfo on Post {
id
title
content
userId
user {
...UserInfo
}
}
query getPost($id: ID!) {
post(id: $id) {
id
title
content
userId
user {
id
name
age
available
birthday
money
gender
}
}
}
query getPosts {
posts {
...PostInfo
}
}
mutation createPost($data: PostInput!) {
createPost(data: $data) {
...PostInfo
}
}
# src/user.graphql
fragment UserInfo on User {
id
name
age
available
birthday
tags
gender
role
}
// src/App.js
import React, { Component } from 'react';
import Post from './Post';
class App extends Component {
render() {
return (
);
}
}
export default App;
// src/Post.js
import React, { Component } from 'react';
import { Query, Mutation, ApolloConsumer } from "react-apollo";
// 导入查询定义,定义的查询名次对应导入对象的方法名称,如 getPost => postQuery.getPost
import postQuery from './post.graphql';
class Post extends Component {
state = {
post: {},
postId: '',
newPost: {
title: '',
content: '',
}
}
render() {
// 由ApolloConsumer传入我们需要的数据,包含:
// data 正常返回时的数据
// loading 正在请求时loading会为true
// error 发生错误时error将会有错误数据
// 这里进行了重命名,将创建post,获取posts列表进行了命名区分
const {
client,
getPostsData, getPostsDataLoading,
createPost, createPostData, createPostLoading,
getPostsDataError
} = this.props;
const { postId, post, newPost } = this.state;
return(
{
// loading状态时将显示...
getPostsDataLoading ?
...
:
(
getPostsDataError ?
// 有错误数据,将会显示错误
{JSON.stringify(getPostsDataError)}
:
// 正常则显示请求到的数据
{JSON.stringify(getPostsData.posts)}
)
}
{
this.setState({ postId: e.target.value })
}}
/>
{JSON.stringify(post)}
this.setState({
newPost: {
...newPost,
title: e.target.value,
}
})}
/>
this.setState({
newPost: {
...newPost,
content: e.target.value,
}
})}
/>
{
createPostLoading ?
...
:
{JSON.stringify(createPostData && createPostData.createPost)}
}
)
}
}
class PostWrap extends Component {
render() {
return (
{(client) => (
// 传入要使用的motation查询
{(
// 方法重命名
createPost,
{
// 状态数据重命名
data: createPostData,
loading: createPostLoading
}
) => (
// 当同时多个查询时,使用这种嵌套模式
{({
// 状态数据重命名
data: getPostsData,
loading: getPostsLoading,
error: getPostsDataError
}) =>
// 将重命名的状态数据和查询方法传递到组件中
// Query指定的查询在组件加载后就会自动发起请求
}
)}
)}
)
}
}
export default PostWrap;
通过这种方式我们可以在react中使用graphql了,这种方式极大方便了我们对请求数据api的管理,而且可以通过整合查询,减少页面的请求次数。
如果你对这系列文章有疑问或发现有错误的地方,欢迎在下方留言讨论。