在 redux 动作创建者中访问 Apollo GraphQL 客户端的最佳方式? [英] Best way to access Apollo GraphQL client inside redux action creators?

查看:20
本文介绍了在 redux 动作创建者中访问 Apollo GraphQL 客户端的最佳方式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面(未经测试的)示例代码中,如果我想访问 actions/math.js 中的 Apollo GraphQL 客户端实例,我必须从 Calculator 组件到事件处理程序,以及从 WrappedCalculator 事件处理程序到动作创建者.

这会导致大量代码膨胀.

actions/math.js 动作创建者访问 GraphQL 客户端实例的更好方法是什么?

示例代码:

常量/Queries.js:

const MUTATION_APPEND_TO_AUDIT_TRAIL = gql`突变 MutationAppendToAuditTrail($mathOperation: String!, $operand1: Float!, $operand2: Float!) {appendToAuditTrail(操作:$mathOperation,operand1:$operand1,operand2:$operand2){ID手术操作数1操作数2}}`;

actions/math.js:

import { INCREMENT_TOTAL_BY, MULTIPLY_TOTAL_BY } from '../constants/ActionTypes';从'../reducers'导入{getTotal};incrementResultBy = (operand, graphQlClient) =>(调度,getState){//使用选择器获取操作前的总数.const total = getTotal(getState());//发送动作以将一个数字添加到 redux 存储中的总数.派遣({类型:types.INCREMENT_TOTAL_BY,操作数,});//将最新的用户活动持久化到服务器.graphQlClient.mutate({突变:MUTATION_APPEND_TO_AUDIT_TRAIL,变量:{mathOperation: '加法',操作数1:总计,操作数2:操作数,},});};multiplyResultBy = (operand, graphQlClient) =>(调度,getState){//使用选择器获取操作前的总数.const total = getTotal(getState());//发送操作以将 redux 存储中的总数乘以一个数字.派遣({类型:types.MULTIPLY_TOTAL_BY,操作数,});//将最新的用户活动持久化到服务器.graphQlClient.mutate({突变:MUTATION_APPEND_TO_AUDIT_TRAIL,变量:{mathOperation: '乘法',操作数1:总计,操作数2:操作数,},});};出口{ incrementResultBy,multiplyResultBy };

components/Calculator.jsx

从'react'导入React;从apollo-client"导入 ApolloClient;常量计算器 = ({全部的,操作数,onPlusButtonClick,onMultiplyButtonClick,}) =>(<div><h2>对 {total} 和 {operand} 执行操作

);DisplayPanel.propTypes = {//Apollo GraphQL 客户端实例.客户端:React.PropTypes.instanceOf(ApolloClient),//来自 Redux 的道具.总计:React.PropTypes.number,操作数:React.PropTypes.number,onPlusButtonClick: React.PropTypes.func,onMultiplyButtonClick: React.PropTypes.func,};导出默认计算器;

容器/WrappedCalculator.js

import { connect } from 'react-redux';从../components/Calculator"导入计算器;import { incrementResultBy, multiplyResultBy } from '../actions';import { getTotal, getOperand } from '../reducers';const mapStateToProps = state =>({总计:getTotal(状态),操作数:getOperand(状态),});const mapDispatchToProps = dispatch =>({onPlusButtonClick: (operand, graphQlClient) =>dispatch(incrementResultBy(operand, graphQlClient)),onMultiplyButtonClick: (operand, graphQlClient) =>调度(multiplyResultBy(操作数,graphQlClient)),});//生成 Apollo 感知、redux 感知的高阶容器.const WrappedCalculator = compose(与阿波罗,连接(mapStateToProps,mapDispatchToProps),)(计算器);导出默认 WrappedCalculator;

解决方案

我为传递 ApolloClient 实例所做的一件事是将 ApolloClient 包装在 Provider 中,如下所示:

ApolloClientProvider.js

class ApolloClientProvider {构造函数(){this.client = new ApolloClient({网络接口:'/graphql'})}}导出默认的新 ApolloClientProvider()

这将创建一个类似 ApolloClient 的单例实例,并且无论您从何处引用它,都将返回与第一次引用 ApolloClientProvider 时初始化的相同 ApolloClient.

从 'ApolloClientProvider' 导入 ApolloClientProviderconst 客户端 = ApolloClientProvider.client

In the (untested) example code below, if I want to access an instance of the Apollo GraphQL client inside actions/math.js, I have to pass it from the Calculator component to event handlers, and from the WrappedCalculator event handlers to the action creators.

This results in a lot of code bloat.

What would be a better way for actions/math.js action creators to access the GraphQL client instance?

Example code:

constants/Queries.js:

const MUTATION_APPEND_TO_AUDIT_TRAIL = gql`
    mutation MutationAppendToAuditTrail($mathOperation: String!, $operand1: Float!, $operand2: Float!) {
        appendToAuditTrail(operation: $mathOperation, operand1: $operand1, operand2: $operand2) {
            id
            operation
            operand1
            operand2
        }
    }
`;

actions/math.js:

import { INCREMENT_TOTAL_BY, MULTIPLY_TOTAL_BY } from '../constants/ActionTypes';
import { getTotal } from '../reducers';

incrementResultBy = (operand, graphQlClient) => (dispatch, getState) {
    // Use selector to get the total prior to the operation.
    const total = getTotal(getState());

    // Send action to add a number to the total in the redux store.
    dispatch({
        type: types.INCREMENT_TOTAL_BY,
        operand,
    });

    // Persist the latest user activity to the server.
    graphQlClient.mutate({
        mutation: MUTATION_APPEND_TO_AUDIT_TRAIL,
        variables: {
            mathOperation: 'ADDITION',
            operand1: total,
            operand2: operand,
          },
        });
};

multiplyResultBy = (operand, graphQlClient) => (dispatch, getState) {
    // Use selector to get the total prior to the operation.
    const total = getTotal(getState());

    // Send action to multiply the total in the redux store by a number.
    dispatch({
        type: types.MULTIPLY_TOTAL_BY,
        operand,
    });

    // Persist the latest user activity to the server.
    graphQlClient.mutate({
        mutation: MUTATION_APPEND_TO_AUDIT_TRAIL,
        variables: {
            mathOperation: 'MULTIPLICATION',
            operand1: total,
            operand2: operand,
          },
        });
};

export { incrementResultBy, multiplyResultBy };

components/Calculator.jsx

import React from 'react';
import ApolloClient from 'apollo-client';

const Calculator = ({
  total,
  operand,
  onPlusButtonClick,
  onMultiplyButtonClick,
}) => (
  <div>
    <h2>Perform operation for {total} and {operand}</h2>
    <button id="ADD" onClick={onPlusButtonClick(() => this.props.operand, this.props.client)}>ADD</button><br />
    <button id="MULTIPLY" onClick={() => onMultiplyButtonClick(this.props.operand, this.props.client)}>MULTIPLY</button><br />
  </div>
);

DisplayPanel.propTypes = {
  // Apollo GraphQL client instance.
  client: React.PropTypes.instanceOf(ApolloClient),

  // Props from Redux.
  total: React.PropTypes.number,
  operand: React.PropTypes.number,
  onPlusButtonClick: React.PropTypes.func,
  onMultiplyButtonClick: React.PropTypes.func,
};
export default Calculator;

containers/WrappedCalculator.js

import { connect } from 'react-redux';

import Calculator from '../components/Calculator';

import { incrementResultBy, multiplyResultBy } from '../actions';
import { getTotal, getOperand } from '../reducers';

const mapStateToProps = state => ({
  total: getTotal(state),
  operand: getOperand(state),
});

const mapDispatchToProps = dispatch => ({
  onPlusButtonClick: (operand, graphQlClient) => dispatch(incrementResultBy(operand, graphQlClient)),
  onMultiplyButtonClick: (operand, graphQlClient) => dispatch(multiplyResultBy(operand, graphQlClient)),
});

// Generate Apollo-aware, redux-aware higher-order container.
const WrappedCalculator = compose(
  withApollo,
  connect(mapStateToProps, mapDispatchToProps),
)(Calculator);

export default WrappedCalculator;

解决方案

One thing that I've done to pass around an ApolloClient instance is to wrap the ApolloClient in a Provider like so:

ApolloClientProvider.js

class ApolloClientProvider {

  constructor() {
    this.client = new ApolloClient({
      networkInterface: '/graphql'
    })
  }
}

export default new ApolloClientProvider()

This will create a singleton like instance of the ApolloClient and wherever you reference it from will return the same ApolloClient that was initialized when the ApolloClientProvider was first referenced.

import ApolloClientProvider from 'ApolloClientProvider'
const client = ApolloClientProvider.client

这篇关于在 redux 动作创建者中访问 Apollo GraphQL 客户端的最佳方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆