前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >在 redux 应用中使用 GraphQL

在 redux 应用中使用 GraphQL

作者头像
疯狂的技术宅
发布于 2019-03-28 02:13:19
发布于 2019-03-28 02:13:19
1.9K00
代码可运行
举报
文章被收录于专栏:京程一灯京程一灯
运行总次数:0
代码可运行

在 Redux 应用中获取和管理数据需要做许多工作。正如 Sashko Stubailo 指出的:

不幸的是,在 Redux 应用程序中异步加载服务器数据的模式还没有建立起来,并且经常需要使用外部帮助程序库,如 redux-saga。 您需要编写自定义代码来调用服务器接口,解释数据,对其进行规范化并将其插入到存储中 - 同时跟踪各种错误和加载状态。

在本教程中,您将学习如何通过 Apollo Client 来获取和管理数据。 您将不再需要编写多个操作调度程序、reducer 和规范化程序来在前端和后端之间获取并同步数据。

在开始本教程之前,请确保:

  • 了解基本的 GraphQL 查询——如果 GraphQL 对您来说完全是陌生的,您需要先学习此教程。
  • 有一定的 React/Redux 经验——否则,请先阅读 react 教程和 redux 教程

在本教程中,我们将学习以下6个小节。

  1. 快速的启动一个服务端环境
  2. 启动一个 redux 脚手架
  3. 增加一个 GraphQL 客户端 (Apollo Client)
  4. 使用 GraphQL 获取数据
  5. 获取更多的数据
  6. 接下来要做的
1. 启动一个服务端环境

首先,我们需要一个 GraphQL 服务器。最简单的方式就是完成这一教程.

如果你不想这么麻烦的话,可以克隆我的 repo, 这个项目和上述教程几乎是一模一样的。我们启动的服务器支持从一个 SQLite 数据库中进行 GraphQL 查询。

让我们启动这个服务器:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ git clone [https://github.com/woniesong92/apollo-starter-kit](https://github.com/woniesong92/apollo-starter-kit)
$ cd apollo-starter-kit
$ npm install
$ npm start

服务器可以通过 http://localhost:8080/graphql 访问。 在该页您可以看到一个如下 GraphQL 界面:

GraphiQL 允许您测试不同的查询,并立即看到从服务器获得的响应。 如果我们不想在响应中看到作者的姓氏和幸运饼干签语条,可以更新成以下查询:

可以看到,这正是我们想要的形式。现在,我们已经确认服务器运行正常,并返回正确的响应,接下来让我们开始构建客户端。

2. 启动 redux 脚手架应用

为了简单起见,我们直接应用一个 redux 脚手架,这样我们就直接获得了一整套开发工具 (比如 Babel, webpack, CSS 等等) 。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ git clone [https://github.com/woniesong92/react-redux-starter-kit.git](https://github.com/woniesong92/react-redux-starter-kit.git)
$ cd react-redux-starter-kit
$ npm install
$ npm start

在浏览器中打开 http://localhost:3000/ :

好极了! 客户端正在运行,现在是开始添加 GraphQL 客户端的时候了。我们的目标是使用 GraphQL 查询,从服务器轻松获取数据并将其呈现在着陆页(HomeView)中。

3. 增加一个 GraphQL 客户端(Apollo 客户端)

安装 apollo-client, react-apollo, 和 graphql-tag。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ npm install apollo-client react-apollo graphql-tag --save

打开 Redux 应用的入口文件 src/containers/AppContainer.js。在这里我们把 redux store 通过 react-redux 中的 provider 传递给子组件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React, { PropTypes } from 'react'
import { Router } from 'react-router'
import { Provider } from 'react-redux'

class AppContainer extends React.Component {
  static propTypes = {
    history: PropTypes.object.isRequired,
    routes: PropTypes.object.isRequired,
    routerKey: PropTypes.number,
    store: PropTypes.object.isRequired
  }

  render () {
    const { history, routes, routerKey, store } = this.props
    return (
      <Provider store={store}>
        <div>
          <Router history={history} children={routes} key={routerKey} />
        </div>
      </Provider>
    )
  }
}

export default AppContainer

首先,我们需要初始化一个 ApolloClient,并将 react-redux 中的 Provider 替换为来自 react-apollo 的 ApolloProvider。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React, { Component, PropTypes } from 'react'
import { Router } from 'react-router'
import ApolloClient, { createNetworkInterface, addTypename } from 'apollo-client'
import { ApolloProvider } from 'react-apollo'

const client = new ApolloClient({
  networkInterface: createNetworkInterface('[http://localhost:8080/graphql'](http://localhost:8080/graphql%27)),
  queryTransformer: addTypename,
})

class AppContainer extends Component {
  static propTypes = {
    history: PropTypes.object.isRequired,
    routes: PropTypes.object.isRequired,
    store: PropTypes.object.isRequired
  }

  render () {
    const { history, routes } = this.props
    return (
      <ApolloProvider client={client}>
        <div>
          <Router history={history} children={routes} />
        </div>
      </ApolloProvider>
    )
  }
}

export default AppContainer

好了!这样我们就把一个 GraphQL 客户端添加进了一个普通的 Redux 应用中。 接下来让我们开始第一个 GraphQL 查询吧。

4. 通过 GraphQL 查询获取数据

进入 src/views/HomeView.js

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'

export class HomeView extends React.Component {
  constructor(props) {
    super(props)
  }

  render () {
    return (
      <div className='home'>
        <h1>Hello World</h1>
      </div>
    )
  }
}

// This is where you usually retrieve the data stored in the redux store (e.g posts: state.posts.data)
const mapStateToProps = (state, { params }) => ({

})

// This is where you usually bind dispatch to actions that are used to request data from the backend. You will call the dispatcher in componentDidMount.
const mapDispatchToProps = (dispatch) => {
  const actions = {}

  return {
    actions: bindActionCreators(actions, dispatch)
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(HomeView)

HomeView 是一个典型的 Redux 容器组件(smart 组件)。如果想要使用 GraphQL 查询语句而不是 action dispatchers 来获取数据,需要做以下改变:

1. 移除 mapDispatchToProps() 和 mapStateToProps()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'

export class HomeView extends React.Component {
  constructor(props) {
    super(props)
  }

  render () {
    return (
      <div className='home'>
        <h1>Hello World</h1>
      </div>
    )
  }
}

export default connect({

})(HomeView)

2. 增加 mapQueriesToProps() 并且定义一个能够获取作者信息的 GraphQL 查询。注意,这个查询语句其实和我们之前在 GraphIQL 界面上测试的语句是一样的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'

export class HomeView extends React.Component {
  constructor(props) {
    super(props)
  }

  render () {
    return (
      <div className='home'>
        <h1>Hello World</h1>
      </div>
    )
  }
}

// NOTE: This will be automatically fired when the component is rendered, sending this exact GraphQL query to the backend.
const mapQueriesToProps = ({ ownProps, state }) => {
  return {
    data: {
      query: gql
        query {
          author(firstName:"Edmond", lastName: "Jones"){
            firstName
            posts {
              title
            }
          }
        }
      
    }
  }
}

export default connect({

})(HomeView)

3. 将从 react-redux 中导出的 connect 方法替换成从 react-apollo 中导出的 connect 方法,同时将 mapQueriesToProps 作为参数传入。在 mapQueriesToProps 连接到 ApolloClient 之后,查询语句将会在 HomeView 被渲染时自动从后端获取数据,然后通过 props 将数据传递下去。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React from 'react'
import { connect } from 'react-apollo' // NOTE: different connect!
import gql from 'graphql-tag' // NOTE: lets us define GraphQL queries in a template language

export class HomeView extends React.Component {
  constructor(props) {
    super(props)
  }

render () {
    return (
      <div className='home'>
        <h1>Hello World</h1>
      </div>
    )
  }
}

const mapQueriesToProps = ({ ownProps, state }) => {
  return {
    data: {
      query: gql
        query {
          author(firstName:"Edmond", lastName: "Jones"){
            firstName
            posts {
              title
            }
          }
        }
      
    }
  }
}

export default connect({
  mapQueriesToProps
})(HomeView)

4. 渲染从 props 中传递下来的数据:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React from 'react'
import { connect } from 'react-apollo' // NOTE: different connect!
import gql from 'graphql-tag' // NOTE: lets us define GraphQL queries in a template language

export class HomeView extends React.Component {
  constructor(props) {
    super(props)
  }

  render () {
    const author = this.props.data.author
    if (!author) {
      return <h1>Loading</h1>
    }

    return (
      <div>
        <h1>{author.firstName}'s posts</h1>
        {author.posts && author.posts.map((post, idx) => (
          <li key={idx}>{post.title}</li>
        ))}
      </div>
    )
  }
}

const mapQueriesToProps = ({ ownProps, state }) => {
  return {
    data: {
      query: gql
        query {
          author(firstName:"Edmond", lastName: "Jones"){
            firstName
            posts {
              title
            }
          }
        }
      
    }
  }
}

export default connect({
  mapQueriesToProps
})(HomeView)

如果进展顺利的话,得到的 HomeView 应该如下所示:

从上面的例子可以看出,如果我们想要获取并渲染数据,我们并不需要写任何的 action dispatcher, reduer, 或者数据规范化方法。我们只需要在客户端中写一条 GraphQL 查询语句!

我们已经达成了目的。不过这个查询语句还是太简单了,如果我们想要显示所有的作者应该怎么做呢?

5. 获取更多的数据

为了获取并显示所有的作者信息,我们需要更新 GraphQL 查询语句以及渲染函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React from 'react'
import { connect } from 'react-apollo' // NOTE: different connect!
import gql from 'graphql-tag' // NOTE: lets us define GraphQL queries in a template language

export class HomeView extends React.Component {
  constructor(props) {
    super(props)
  }

render () {
    const authors = this.props.data.authors
    if (!authors) {
      return <h1>Loading</h1>
    }

    return (
      <div>
        {authors.map((author, idx) => (
          <div key={'author-'+idx}>
            <h1>{author.firstName}'s posts</h1>
            {author.posts && author.posts.map((post, idx) => (
              <li key={idx}>{post.title}</li>
            ))}
          </div>
        ))}
      </div>
    )
  }
}

const mapQueriesToProps = ({ ownProps, state }) => {
  return {
    data: {
      query: gql
        query {
          authors {
            firstName
            posts {
              title
            }
          }
        }
      
    }
  }
}

export default connect({
  mapQueriesToProps
})(HomeView)

然而,一旦你刷新页面,你将发现在 console 中会出现这么一条错误:

ApolloError {graphQLErrors: Array[1], networkError: undefined, message: “GraphQL error: Cannot query field “authors” on type “Query”. Did you mean “author”?”}

对了!在我们的 GraphQL 服务器中,并没有定义如何获取 authors

现在让我们回到服务端,打开 apollo-starter-kit/data/resolvers.js 文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { Author, FortuneCookie } from './connectors';

const resolvers = {
  Query: {
    author(_, args) {
      return Author.find({ where: args });
    },
    getFortuneCookie() {
      return FortuneCookie.getOne()
    }
  },
  Author: {
    posts(author) {
      return author.getPosts();
    },
  },
  Post: {
    author(post) {
      return post.getAuthor();
    },
  },
};

export default resolvers;

从查询语句的处理函数中可以看出,现在我们的 GraphQL 服务器只能理解 authorgetFortuenCookie 语句。现在我们要教会它处理 authors 查询。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { Author, FortuneCookie } from './connectors';

const resolvers = {
  Query: {
    author(_, args) {
      return Author.find({ where: args });
    },
    getFortuneCookie() {
      return FortuneCookie.getOne()
    },
    authors() { // the query "authors" means returning all authors!
      return Author.findAll({})
    }
  },
  ...
};

export default resolvers;

还没结束,打开 apollo-starter-kit/data/schema.js

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const typeDefinitions = 
...
type Query {
  author(firstName: String, lastName: String): Author
  getFortuneCookie: String
}
schema {
  query: Query
}
;

export default [typeDefinitions];

这个 Schema 表明了哪些查询语句是服务器所接受的。它暂时不接受 authors 查询,现在让我们更新一下。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const typeDefinitions = 
...

type Query {
  author(firstName: String, lastName: String): Author
  getFortuneCookie: String,
  authors: [Author] // 'authors' query should return an array of 
                    // Author
}
schema {
  query: Query
}
;

export default [typeDefinitions];

现在既然我们的 GraphQL 服务器知道了 "authors" 查询的含义,让我们回到客户端。因为我们已经更新了查询语句,所以其实不用改变任何东西。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export class HomeView extends React.Component {
...

const mapQueriesToProps = ({ ownProps, state }) => {
  return {
    data: {
      query: gql
        query {
          authors {
            firstName
            posts {
              title
            }
          }
        }
      
    }
  }
}

export default connect({
  mapQueriesToProps
})(HomeView)

通过这条查询语句我们就可以得到所有的作者姓氏以及他们的作品列表。接下来让我们刷新一下浏览器看看是否得到了正确的数据。

如果一切顺利的话,你的 HomeView 将会看起来像这个样子。

6. 接下来

这篇教程只探索了 GraphQL 的一小部分,还有许多内容尚未涉及,比如在服务端更新数据或者使用其他的服务端(如 Rails)。

不过我准备在后续的教程中介绍这些内容,您可以阅读 Sashko 的 文章 或者 Apollo Client 文档来更好的理解 GraphQL 的原理 (比如,当我们把 Provider 替换成 ApolloProvider 时到底发生了什么?).

深入研究 GitHunt 的源码也是一种很好的学习方式,这是一个全栈的 Apollo 客户端及服务端 app 样例。

来源:http://www.zcfy.cc/article/how-to-use-graphql-in-your-redux-app-freecodecamp-4080.html

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-08-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 京程一灯 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
用TS+GraphQL查询SpaceX火箭发射数据[每日前端夜话0x81]
近一两年来 GraphQL 和 TypeScript 的使用都程爆发式增长,当两者与React结合使用时,它们可以为开发人员提供理想的开发体验。
疯狂的技术宅
2019/06/18
3K0
用TS+GraphQL查询SpaceX火箭发射数据[每日前端夜话0x81]
React + Redux + GraphQL 环境搭建
之前闲着无聊写的一个 Redux 项目,今天突然想把它做成动态数据源,很早之前使用 Gatsby 的时候尝试过 GraphQL 觉得不错,所以就试着集成了一下。
szhshp
2022/09/21
3430
【重学React】动手实现一个react-redux
react-redux 是 redux 官方 React 绑定库。它帮助我们连接UI层和数据层。本文目的不是介绍 react-redux 的使用,而是要动手实现一个简易的 react-redux,希望能够对你有所帮助。
胡哥有话说
2019/10/24
3.2K0
redux架构基础
本文书接 从flux到redux , 是《深入浅出react和redux》为主的比较阅读笔记。
一粒小麦
2020/01/02
1.2K0
使用Redux制作一个TodoList
在组件化开发的 web 前端当中,经常的需要在不同的组件之间进行通信以及一些数据共享,那么我们就需要使用像 Vuex 那样的状态管理工具,在 React 当中,经常使用 Redux 来做状态管理工具。
小小杰啊
2022/12/21
4700
使用Redux制作一个TodoList
React性能优化 -- 利用React-Redux
注意这里面,如果可以在渲染virtual DOM之前就可以判断渲染结果不会有变化,那么可以直接不进行virtual DOM的渲染和比较,速度会更快。
IMWeb前端团队
2019/12/03
1K0
React性能优化 -- 利用React-Redux
GraphQL学习第十篇 -Vue中使用Vue-apollo实现下拉加载更多
在Vue中集中Vue-apollo以后(如何集成请查看本专栏第六篇),就可以使用它进行分页加载了,主要有以下两种方法:
越陌度阡
2020/11/26
8790
redux、mobx、concent特性大比拼, 看后生如何对局前辈
redux、mobx本身是一个独立的状态管理框架,各自有自己的抽象api,以其他UI框架无关(react, vue...),本文主要说的和react搭配使用的对比效果,所以下文里提到的redux、mobx暗含了react-redux、mobx-react这些让它们能够在react中发挥功能的绑定库,而concent本身是为了react贴身打造的开发框架,数据流管理只是作为其中一项功能,附带的其他增强react开发体验的特性可以按需使用,后期会刨去concent里所有与react相关联的部分发布concent-core,它的定位才是与redux、mobx 相似的。
腾讯新闻前端团队
2020/04/06
4.6K0
redux、mobx、concent特性大比拼, 看后生如何对局前辈
字节前端面试题总结
由ES6的继承规则得知,不管子类写不写constructor,在new实例的过程都会给补上constructor。
buchila11
2022/07/27
1.6K0
react+redux+webpack教程3
现代web页面里到处都是ajax,所以处理好异步的代码非常重要。 这次我重新选了个最适合展示异步处理的应用场景——搜索新闻列表。由于有现成的接口,我们就不用自己搭服务了。 我在网上随便搜到了一个新闻服务接口,支持jsonp,就用它吧。 一开始,咱们仍然按照action->reducer->components的顺序把基本的代码写出来。先想好要什么功能, 我设想的就是有一个输入框,旁边一个搜索按钮,输入关键字后一点按钮相关的新闻列表就展示出来了。 首先是action,现在能想到的动作就是把新闻列表放到仓库里,
前朝楚水
2018/04/03
1K0
GraphQL学习第七篇 -Vue中使用Vue-apollo进行查询操作
在Vue中集中Vue-apollo以后(如何集成请查看本专栏第六篇),就可以使用它进行查询数据了。
越陌度阡
2020/11/26
1.3K0
React 进阶 - React Redux
应用初始化时候,只请求一次数据,然后通过状态管理把数据存起来,需要数据的组件只需要从状态管理中‘拿’就可以了。
Cellinlab
2023/05/17
9530
React 进阶 - React Redux
现代Web开发系列教程_04
本篇使用redux结合react重写刚才那个很简单的hello world示例。 redux的理念 redux有三个重要的理念:单一数据源、状态是只读的、使用纯函数转换状态。具体见链接 安装redux与react-redux 1 npm install redux react-redux --save 状态转换纯函数 web-src/js/components/GreetingConstant.js 1 export const CHANGE_NAME = 'CHANGE_NAME'; web-src/
jeremyxu
2018/05/10
7230
GraphQL 入门详解
传统的api调用一般获取到的是后端组装好的一个完整对象,而前端可能只需要用其中的某些字段,大部分数据的查询和传输工作都浪费了。graphQL提供一种全新数据查询方式,可以只获取需要的数据,使api调用更灵活、高效和低成本。
Nealyang
2019/09/29
2.1K0
GraphQL 入门详解
React高级篇(一)从Flux到Redux,react-redux
React框架本身只应用于View,如果基于MVC模式开发,还需要Model和Control层,这样催生了Flux的产生,而Redux是基于Flux理念的一种解决方式。
娜姐
2021/01/14
2K1
React高级篇(一)从Flux到Redux,react-redux
彻底让你理解redux
state才是真正的前端数据库,它存储着这个应用所有需要的数据。 这里拿一个简单的例子说明下,为什么说简单的例子呢,因为简单到不应该使用redux。。。 运行效果如图(学习redux这个例子被介绍烂了):
Nealyang
2019/09/29
5160
彻底让你理解redux
GraphQL 实战篇之前端Vue+后端Nest
前面我们介绍了GraphQL的概念和基础知识,这篇文章记录下使用Nestjs+GraphQL搭建Node服务。
winty
2021/05/18
1.2K0
GraphQL 实战篇之前端Vue+后端Nest
Redux 包教包会(二):趁热打铁,重拾初心
在这一部分中,我们将趁热打铁,运用上篇教程学到的 Redux 三大核心概念来将待办事项的剩下部分重构完成,它涉及到将 TodoList 和 Footer 部分的相关代码重构到 Redux,并使用 Redux combineReducers API 进行逻辑拆分和组合,使得我们可以在使用 Redux 便利的同时,又不至于让应用的逻辑看起来臃肿不堪,复用 React 组件化的便利,我们可以让状态的处理也 “组件化”。最后,我们将让 React 回归初心——专注于展现用户界面,通过“容器组件”和“展示组件”将逻辑和状态进一步分离。
一只图雀
2020/04/07
2.3K0
如何在 React.js 项目中使用 GraphQL
GraphQL 由于其灵活性和高效性,已经成为构建 API 的热门选择。当与 React.js 结合使用时,这个强大的 JavaScript 库为创建动态、响应式的 Web 应用程序打开了无限的可能性。在本指南中,我们将介绍如何将 GraphQL 无缝集成到您的 React.js 项目中。
泽霖
2023/11/12
5300
React-Redux 对Todolist修改
在单独使用redux的时候 需要手动订阅store里面 感觉特别麻烦 不错的是react有一个组件可以帮我们解决这个问题, 那就是react-redux。
憧憬博客
2020/07/21
6300
React-Redux 对Todolist修改
推荐阅读
相关推荐
用TS+GraphQL查询SpaceX火箭发射数据[每日前端夜话0x81]
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文