在 redux Action Creators 中访问 Apollo GraphQL 客户端的最佳方式?

Eli*_*eal 1 javascript apollo graphql react-redux

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

这会导致大量代码膨胀。

actions/math.js对于操作创建者来说,访问 GraphQL 客户端实例的更好方式是什么?

示例代码:

常量/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
        }
    }
`;
Run Code Online (Sandbox Code Playgroud)

动作/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 };
Run Code Online (Sandbox Code Playgroud)

组件/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;
Run Code Online (Sandbox Code Playgroud)

容器/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;
Run Code Online (Sandbox Code Playgroud)

wmc*_*ain 5

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

ApolloClientProvider.js

class ApolloClientProvider {

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

export default new ApolloClientProvider()
Run Code Online (Sandbox Code Playgroud)

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

import ApolloClientProvider from 'ApolloClientProvider'
const client = ApolloClientProvider.client
Run Code Online (Sandbox Code Playgroud)