react+graphql起手和特性介绍(三)
紧接上篇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 = ( <ApolloProvider client={client}> <App /> </ApolloProvider> ); 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 ( <div> <Post/> </div> ); } } 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( <div> <div> { // loading状态时将显示... getPostsDataLoading ? <div>...</div> : ( getPostsDataError ? // 有错误数据,将会显示错误 <div>{JSON.stringify(getPostsDataError)}</div> : // 正常则显示请求到的数据 <div>{JSON.stringify(getPostsData.posts)}</div> ) } </div > <hr /> <div> <input type="text" name="postId" value={postId} onChange={(e) => { this.setState({ postId: e.target.value }) }} /> <button onClick={() => { // client 也是props传过来的对象,可以让我们主动发起请求 client.query({ // 对应定义的 getPost 查询 query: postQuery.getPost, // 设置请求参数 variables: { id: postId } }).then(({ data: { post } }) => { this.setState({ post }) }) }}> getPost </button> <div>{JSON.stringify(post)}</div> </div> <hr/> <div> <input type="text" value={newPost.title} onChange={(e) => this.setState({ newPost: { ...newPost, title: e.target.value, } })} /> <input type="text" value={newPost.content} onChange={(e) => this.setState({ newPost: { ...newPost, content: e.target.value, } })} /> <button onClick={() => createPost({ // createPost是ApolloConsumer传过来的包装好的请求方法, // 这里只用设置请求参数,loading,data,error 将会通过props // 传递进来 variables: { data: newPost } })}> createPost </button> { createPostLoading ? <div>...</div> : <div> {JSON.stringify(createPostData && createPostData.createPost)} </div> } </div> </div > ) } } class PostWrap extends Component { render() { return ( <ApolloConsumer> {(client) => ( // 传入要使用的motation查询 <Mutation mutation={postQuery.createPost}> {( // 方法重命名 createPost, { // 状态数据重命名 data: createPostData, loading: createPostLoading } ) => ( // 当同时多个查询时,使用这种嵌套模式 <Query query={postQuery.getPosts} > {({ // 状态数据重命名 data: getPostsData, loading: getPostsLoading, error: getPostsDataError }) => // 将重命名的状态数据和查询方法传递到组件中 // Query指定的查询在组件加载后就会自动发起请求 <Post {...{ client, getPostsData, getPostsLoading, getPostsDataError, createPost, createPostData, createPostLoading }} />} </Query> )} </Mutation> )} </ApolloConsumer> ) } } export default PostWrap;
通过这种方式我们可以在react中使用graphql了,这种方式极大方便了我们对请求数据api的管理,而且可以通过整合查询,减少页面的请求次数。
如果你对这系列文章有疑问或发现有错误的地方,欢迎在下方留言讨论。
相关推荐
游走的豚鼠君 2020-11-10
不知道该写啥QAQ 2020-08-02
不知道该写啥QAQ 2020-06-10
81417707 2020-10-30
ctg 2020-10-14
小飞侠V 2020-09-25
PncLogon 2020-09-24
jipengx 2020-09-10
颤抖吧腿子 2020-09-04
wwzaqw 2020-09-04
maple00 2020-09-02
青蓝 2020-08-26
罗忠浩 2020-08-16
liduote 2020-08-13
pengruiyu 2020-08-01
wmd看海 2020-07-27
孝平 2020-07-18
Eduenth 2020-07-05