緊接上篇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
安裝如下前端依賴node
npm install react-apollo graphql-tag graphql apollo-client apollo-cache-inmemory apollo-link-http
各個依賴包的做用:react
而後咱們進行react和graphql的整合webpack
// 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-loaderweb
// 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文件npm
# 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的管理,並且能夠經過整合查詢,減小頁面的請求次數。
若是你對這系列文章有疑問或發現有錯誤的地方,歡迎在下方留言討論。segmentfault