在Redux操作创建者内部访问Apollo GraphQL客户端的最佳方法? [英] Best way to access Apollo GraphQL client inside redux action creators?

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

问题描述

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

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.

这导致大量代码膨胀.

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

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

示例代码:

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;

容器/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;

推荐答案

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

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()

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

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天全站免登陆