react+graphql起手和特性介绍(三)

news/2024/12/27 5:15:52

紧接上篇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的管理,而且可以通过整合查询,减少页面的请求次数。
如果你对这系列文章有疑问或发现有错误的地方,欢迎在下方留言讨论。


http://www.niftyadmin.cn/n/4581896.html

相关文章

解析域名、修改默认端口、打包java项目和连接数据库并导入数据

为什么80%的码农都做不了架构师&#xff1f;>>> 接上文&#xff1a;搭建云服务器并部署发布Java项目 1、购买腾讯云服务器的学生套餐时&#xff0c;再加8元即可获得一个自己的域名 然后点云产品&#xff0c;进入到云解析&#xff0c;进行域名和你的云服务器的公网i…

iqoo5什么时候上市

iQOO5系列将于8月17日正式发布 据官方公布的海报显示&#xff0c;iQOO 5系列首发120W超快闪充技术&#xff0c;5分钟可以从0%充至50%&#xff0c;15分钟即可将设备充至100%电量&#xff08;4000mAh&#xff09;。 iqoo5新品活动 优惠力度空前 https://mall.jd.com/index-100008…

Native Socket.IO and Android

原文链接地址&#xff1a;http://socket.io/blog/native-socket-io-and-android/ 在本教程中我们将学习如何创建一个聊天客户端用socket . io Node. JS做为聊天服务器 ,我们的 nativate安卓客户端 ! 如果你想直接跳转到代码,它在 GitHub 。 否则,继续读下去! #介绍 跟随,首先克…

Linux命令之单引号、双引号、反引号

1.单引号 ( ) 单引号&#xff0c;不具有变量置换的功能&#xff0c;即单引号会告诉shell忽略所有的特殊字符2.双引号(" ") 双引号&#xff0c;具有变量置换的功能&#xff0c;即双引号之要求忽略大多数特殊字符&#xff0c;除了$&#xff08;使用变量前导符&#xff…

iQOO5和iQOO5pro有什么区别

外观方面iQOO5还是是颇为养眼的&#xff0c;其采取上半年流行的曲面挖孔屏设计&#xff0c;得益于四周边框的极窄化处理&#xff0c;iQOO5屏占比也是十分的可观&#xff0c;背部机身方面iQOO5则为玻璃材质&#xff0c;后置摄像头以居左式矩形状排列&#xff0c;造型风格较为简约…

OkHttp各种请求方法

原文地址&#xff1a;http://blog.csdn.net/liyuchong2537631/article/details/48369403 支持 SPDY &#xff0c;共享同一个 Socket 来处理同一个服务器的所有请求 如果 SPDY 不可用&#xff0c;则通过连接池来减少请求延时 无缝的支持GZIP来减少数据流量 缓存响应数据来减少…

Linux-Nginx-生产ssl密钥对

cd /usr/local/nginx/conf yum install -y openssl # 安装使用的命令 openssl genrsa -des3 -out tmp.key 2048 //key文件为私钥 genrsa&#xff1a;生成rsa格式的私钥&#xff0c;2048是长度&#xff0c;名字叫tmp.key,且生成密码。 openssl rsa -in tmp.key -out aminglinux…

荣耀x10和小米10x的区别 哪个好

红米10X采用6.57英寸E2材质的三星AMOLED屏幕&#xff0c;支持屏幕指纹识别。红米10X正面屏幕采用了水滴屏的设计&#xff0c;相信对于屏幕有强迫症的小伙伴肯定不会喜欢&#xff01; 荣耀x10更多使用感受和评价&#xff1a;https://www.huawei.com/x10 小米10x更多使用感受和评…