Dynamic mutation document for react-apollo

2020-07-27 03:14发布

问题:

I need to change my mutation document dynamically to be able to create multiple items in a single mutation. So I have this function createOrderName that takes an integer and be able to create the correct mutation document. Eg. createOrderName(2) gets

mutation createOrderMut($input0: AddToOrderMenuItemConnectionInput!, $input1: AddToOrderMenuItemConnectionInput!) {
  input0: addToOrderMenuItemConnection (input:$input0) {
    changedOrderMenuItem {
      id
    }
  }
  input1: addToOrderMenuItemConnection (input:$input1) {
    changedOrderMenuItem {
      id
    }
  }
}

And my container is as follow.

const CartContainer = compose(
  graphql(createOrderName(2), {
    props: ({ mutate }) => ({
      addToOrderMenuItem: (menus, orderId) => mutate({
        variables: createOrdersInput(menus, orderId)
      })
    })
  })
)(CartView)

Now how can I pass an integer value to this mutation in order for it to create the correct mutation document? Currently it's fix to 2, but I need it to be more flexible so I can create any number of items...

回答1:

This sounds like an unfortunate limitation of the backend you're working with. The right way to do a batch mutation would be to have a single mutation field on the server that accepts a list argument with all of the items you want to insert. Thus, Apollo isn't designed to support such dynamic query generation with the standard react-apollo API. That's because we strongly believe that working with static queries is much better than generating fields at runtime: https://dev-blog.apollodata.com/5-benefits-of-static-graphql-queries-b7fa90b0b69a#.hp710vxe7

Given the situation, though, sounds like generation the mutation string dynamically is a good option. You can do this by using Apollo directly instead of through the graphql HoC. You can use the withApollo HoC to do this: http://dev.apollodata.com/react/higher-order-components.html#withApollo

import { withApollo } from 'react-apollo';

const MyComponent = ({ client }) => {
  function mutate() {
    const dynamicMutationString = // generate mutation string here

    client.mutate({
      mutation: gql`${dynamicMutationString}`,
      variables: { ... },
    }).then(...);
  }

  return <button onClick={mutate}>Click here</button>;
}

const MyComponentWithApollo = withApollo(MyComponent);

We built this extra API for just this purpose - when the standard stuff is not enough.

Here are the docs for mutate btw: http://dev.apollodata.com/core/apollo-client-api.html#ApolloClient.mutate



回答2:

I'm not sure if I can answer your question with your current implementation, so I'm going to urge you to rethink your mutation definition and use GraphQLList and GraphQLInputObject.

So, depending on the fields you need to mutate:

args: {
  input: {
    type: new GraphQLList(new GraphQLInputObjectType({
      name: 'inputObject',
      description: 'Your description here',
      fields: {
        id: { type: GraphQLInt }
      },
    })),
  },
},

This way you can provide n-number of objects into your mutate call, and get a list back on your type:

{
  mutation myMutation {
    addToOrderMenuItemConnection(input: [{ id: 123 }, { id: 456 }]) {
      id
    }
  }
}

Again, I'm not 100% familiar with your end-goal, but I think this would give you flexibility for future changes/updates as well since you're dealing with an object input rather than individual arguments, which would also (hopefully) insulate you from future breaking-changes.