Search code examples
javascriptreactjsrelayjs

How to get the ID of a new object from a mutation?


I have a createObject mutation that returns the ID of the new object.

After it returns I want to redirect to a detail page about the new object.

How can I get response fields from a mutation in the containing component using react/relay?

E.g. my createObject page contains the mutation with code like:

var onFailure = (transaction) => {

};

var onSuccess = () => {
  redirectTo('/thing/${newthing.id}');   // how can I get this ID?
};

// To perform a mutation, pass an instance of one to `Relay.Store.update`
Relay.Store.update(new AddThingMutation({
  userId: this.props.userId,
  title: this.refs.title.value,
}), { onFailure, onSuccess });
}

newthing should be the object created by the mutation, but how can I get hold of it?


Solution

  • Normally we would configure the client-side of the mutation with RANGE_ADD and return a new thingEdge from the server side of the mutation, but here you don't have a range on the client to add the new node to. To tell Relay to fetch an arbitrary field, use the REQUIRED_CHILDREN config.

    Server side mutation

    var AddThingMutation = mutationWithClientMutationId({
      /* ... */
      outputFields: {
        newThingId: {
          type: GraphQLID,
          // First argument: post-mutation 'payload'
          resolve: ({thing}) => thing.id,
        },
      },
      mutateAndGetPayload: ({userId, title}) => {
        var thing = createThing(userId, title);
        // Return the 'payload' here
        return {thing};
      },
      /* ... */
    });
    

    Client side mutation

    class AddThingMutation extends Relay.Mutation {
      /* ... */
      getConfigs() {
        return [{
          type: 'REQUIRED_CHILDREN',
          // Forces these fragments to be included in the query
          children: [Relay.QL`
            fragment on AddThingPayload {
              newThingId
            }
          `],
        }];
      }
      /* ... */
    }
    

    Example usage

    var onFailure = (transaction) => {
      // ...
    };
    
    var onSuccess = (response) => {
      var {newThingId} = response.addThing;
      redirectTo(`/thing/${newThingId}`);
    };
    
    Relay.Store.update(
      new AddThingMutation({
        title: this.refs.title.value,
        userId: this.props.userId,
      }), 
      {onSuccess, onFailure}
    );
    

    Note that any fields you query for by using this technique will be made available to the onSuccess callback, but will not be added to the client side store.