2017-02-27 30 views
1

在下面的未经测试的示例代码中,如果我想访问actions/math.js中的Apollo GraphQL客户端实例,我必须将它从Calculator组件传递给事件处理程序,并从WrappedCalculator事件处理程序传递给动作创建者。在Redux动作创建器中访问Apollo GraphQL客户端的最佳方式是什么?

这会导致很多代码膨胀。

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; 

容器,我已经做了传递个ApolloClient实例/ 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; 
+0

可能有点晚...但由于查询和突变是异步的,所以您需要使用thunk中间件。 Thunk中间件方便地允许您为动作创建者提供额外的arg - 所以您可以将其配置为为客户端提供额外的参数。请参阅:https://github.com/gaearon/redux-thunk#injecting-a-custom-argument – WickyNilliams

回答

1

一件事是包裹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 
0

基于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; 
} 

该代码使用阿波罗的客户端(V 1.1.1)

0

在你index.js文件,必须const client = new ApolloClient({...})

,而不是让它export client = new ApolloClient({...})

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

相关问题