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

本文是小编为大家收集整理的关于在redux动作创建者内部访问Apollo GraphQL客户端的最佳方式?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

在下面的(未经测试的)示例代码中,如果我想访问actions/math.js内的Apollo GraphQl客户端的实例,我必须将其从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
        }
    }
`;

动作/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 };

组件/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;

容器/包装Calculator.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包裹在这样的提供商中:

:

apolloclientprovider.js

class ApolloClientProvider {

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

export default new ApolloClientProvider()

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

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

其他推荐答案

在您的index.js文件中,您有const client = new ApolloClient({...}):

改为export const client = new ApolloClient({...})

并将其作为import { client } from './index'导入,或者您可以通过所有道具.

其他推荐答案

基于WMCBAIN答案,我还创建并注册了客户提供商:

apolloclientprovider.ts

import ApolloClient, { createNetworkInterface } from "apollo-client";
export class ApolloClientProvider {

client: ApolloClient;

constructor(private settings: Settings) {
  this.client = new ApolloClient({
     networkInterface: createNetworkInterface({
       uri: "https://myGraphQLServer/api/data"
     })
  })
 }
}

app.ts

//register the provider
app.service("apolloClientProvider", ApolloClientProvider);

clientservice.ts

class ClientService {

apolloClient: ApolloClient;

constructor(private apolloClientProvider: ApolloClientProvider) {
    this.apolloClient = apolloClientProvider.client;
}

此代码使用apollo-client(v 1.1.1)

本文地址:https://www.itbaoku.cn/post/1938096.html

问题描述

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

其他推荐答案

In your index.js file, you have const client = new ApolloClient({...}):

instead make it export const client = new ApolloClient({...})

And import it as import { client } from './index', or you can pass through all the props.

其他推荐答案

Based on wmcbain answer I also created and registered a client provider:

ApolloClientProvider.ts

import ApolloClient, { createNetworkInterface } from "apollo-client";
export class ApolloClientProvider {

client: ApolloClient;

constructor(private settings: Settings) {
  this.client = new ApolloClient({
     networkInterface: createNetworkInterface({
       uri: "https://myGraphQLServer/api/data"
     })
  })
 }
}

app.ts

//register the provider
app.service("apolloClientProvider", ApolloClientProvider);

clientService.ts

class ClientService {

apolloClient: ApolloClient;

constructor(private apolloClientProvider: ApolloClientProvider) {
    this.apolloClient = apolloClientProvider.client;
}

This code uses apollo-client (v 1.1.1)