经过前一章节的基础介绍,大家对graphql已经有了基本的认识,也可以搭建一个简易的graphql server。那么在react前端项目中,怎么去连接graphql server和请求到数据呢?
Relay是什么?
在react应用中,relay提供了一套请求和管理graphql数据的方案。它是一套基于GraphQL和React的框架,将这两者结合,在原来React组件的基础上,进一步将请求封装进组件。
下面将一步步介绍在react项目中怎么使用relay。
基础搭建
使用create-react-app快速搭建一个react项目
npx create-react-app relay-test
yarn add --dev customize-cra react-app-rewired
搭建Relay
安装react-relay
yarn add react-relay
安装babel解析relay的插件babel-plugin-relay,同时配置.babelrc
relay插件需要在其他babel插件或者babel preset之前运行,保证graphql语法能够正确的转译
yarn add --dev babel-plugin-relay graphql
// .babelrc
{
"plugins": [
["relay", {
"schema": "schema.graphql",
"artifactDirectory": "./src/__generated__"
}]
]
}
安装relay解析 relay-compiler,同时在package.json中添加relay脚本
yarn relay之后,会在src目录下自动生成__generated__目录
yarn add --dev relay-compiler
// package.json
"scripts": {
"relay": "relay-compiler --src ./src --schema ./schema.graphql --artifactDirectory ./src/__generated__",
"start": "yarn relay && react-app-rewired start"
}
在根目录创建文件config-overrides.js, 覆盖webpack相关配置。
注意:devServer的配置中,我们将/graphql请求代理到http://localhost:4000/,也就是我们在第一章节搭建的graphql server,之后可以通过/graphql请求拿到数据。
const {
override,
addBabelPlugins,
addWebpackAlias,
addDecoratorsLegacy,
fixBabelImports,
disableEsLint
} = require('customize-cra');
const path = require('path');
module.exports = {
webpack: override(
// 添加babel插件relay
...addBabelPlugins(['relay', { artifactDirectory: './src/__generated__' }]),
// 添加alias
addWebpackAlias({
'src': path.resolve(__dirname, 'src')
}),
// 项目中使用antd,需要先安装antd和babel-plugin-import
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: 'css'
})
),
devServer (configFunction) {
return (proxy, allowedHost) => {
const config = configFunction({
'/graphql': {
target: 'http://localhost:4000/',
changeOrigin: true
}
}, allowedHost)
return config
}
}
}
业务场景
基于graqhql server的用户列表数据,我们先尝试用graphql请求用户列表users,在前端显示出一个用户的表格。
目录结构如下
schema
在根目录下创建schema.graphql,定义客户端可用的query和mutation。
注意:与server端的schema保持一致
type Query {
users: [User]!
user (id: ID!): User!
}
type Mutation {
addUser (id: ID!, name: String!, email: String!, age: Int): User
updateUser (id: ID!, name: String, email: String, age: Int): User
deleteUser(id: ID!): User!
}
type User {
id: ID!
key: Int!
name: String!
email: String!
age: Int!
}
QueryRenderer
Relay框架提供了QueryRenderer这样一个高阶组件(HOC)来封装React组件和GraphQL请求。这个组件接受四个Props:environment、query、variables以及render。environment需要配置网络请求和Store;query接受的便是GraphQL请求;variables接受GraphQL请求中需要的变量,最后render用来定义组件的渲染。引用出处>>
注意: 在relay中,组件定义的Operation name必须是以文件名开头,以Query或Mutation结尾。比如src/AppRoute.js中定义的query的Operation name是AppRouteQuery。
// src/AppRoute.js
import React from 'react';
import { graphql, QueryRenderer } from 'react-relay';
import Home from './pages/home';
import environment from './lib/environment';
const AuthRoute = () => {
return <QueryRenderer
environment={environment}
query={graphql`
query AppRouteQuery {
users {
key
name
age
email
}
}
`}
render={({error, props}) => {
if (props) {
return <Home data={props.users}/>
}
}}
/>
}
export default AuthRoute;
environment用来配置网络请求和Store。这里的Store是RecordStore。Relay会为每一个请求节点记录一个id,在store中存为一个record。
// src/lib/environment.js
import {
Environment,
Network,
RecordSource,
Store
} from 'relay-runtime';
const modernEnvironment = new Environment({
network: Network.create(async (operation, variables) => {
const response = await fetch('/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: operation.text,
variables,
})
})
return response.json();
}),
store: new Store(new RecordSource())
})
export default modernEnvironment;
Home表格渲染界面,用antd Table组件渲染。
// src/pages/home/index
import {Table} from 'antd';
export default function Home (props) {
const columns = [{
title: 'name',
dataIndex: 'name',
key: 'name'
}, {
title: 'age',
dataIndex: 'age',
key: 'age'
}, {
title: 'email',
dataIndex: 'email',
key: 'email'
}]
return <Table dataSource={props.data} columns={columns} />;
}
项目启动
yarn start 执行后,先会对src中的relay进行解析,生成src/__generated__目录,里面存放解析好的.graphql.js文件,然后启动客户端服务,打开localhost:3000,可以看到用户列表已经请求到并渲染出来。
至此,大功告成!
最后
Fragment和Mutation的relay用法,暂未做一一演示。有兴趣的童靴可以继续研究下。