Dan Train
Dan Train

Reputation: 21

How to update connection metadata in client-side store?

I'm attempting to learn Relay by implementing TodoMVC from scratch. I can query my data like this which is working well:

query {
  allTodos(first: 100) {
    totalCount
    completedCount
    edges {
      node {
        id
        text
        completed
      }
    }
  }
}

I got the idea to add the totalCount and completedCount metadata to the connection from here: http://graphql.org/learn/pagination/#end-of-list-counts-and-connections
It's similar in this example: https://github.com/graphql/swapi-graphql/blob/master/src/schema/index.js#L78

Now I am writing a mutation to change the completed field of a Todo given its id. I gather I will need to return the new completedCount in the mutation payload, but I'm not sure how to implement getConfigs() to update this in the client-side store. I don't have an id for the connection, right? Is there is a flaw in my schema design? Thanks!

Upvotes: 2

Views: 278

Answers (1)

Brandon
Brandon

Reputation: 7966

Assuming your mutation returns a viewer, you'll need to add the viewer to your fatQuery and getConfigs. I think this tutorial might be helpful. Here's the excerpt relevant to your task:

Adding a Todo is more complex. The reason for this is that we need to update not only the state of a Todo object that we will create, but also a connection where it is stored - the count of Todos will change, as well as the listing of Todo nodes in edges.

import Relay from 'react-relay';

export default class AddTodoMutation extends Relay.Mutation {
  static fragments = {
    viewer: () => Relay.QL`fragment on ReindexViewer {
      id
      allTodos {
        count,
      }
    }`
  };

  getMutation() {
    return Relay.QL`mutation{ createTodo }`;
  }

  getVariables() {
    return {
      text: this.props.text,
      complete: false,
    };
  }

  getFatQuery() {
    return Relay.QL`
      fragment on _TodoPayload {
        changedTodoEdge,
        viewer {
          id,
          allTodos {
            count
          }
        }
      }
    `;
  }

  getConfigs() {
    return [{
      type: 'RANGE_ADD',
      parentID: this.props.viewer.id,
      connectionName: 'allTodos',
      edgeName: 'changedTodoEdge',
      rangeBehaviors: {
        '': 'prepend',
      },
    }, {
      type: 'FIELDS_CHANGE',
      fieldIDs: {
        viewer: this.props.viewer.id,
      },
    }];
  }

  getOptimisticResponse() {
    return {
      changedTodoEdge: {
        node: {
          text: this.props.text,
          complete: false,
        },
      },
      viewer: {
        id: this.props.viewer.id,
        allTodos: {
          count: this.props.viewer.allTodos.count + 1,
        },
      },
    };
  }
}

In order to perform this mutation, we need some data that might not be available to the component - the id of viewer object and count of allTodos connection. Therefore we need to specify fragments for the mutation same way as we specify them for containers.

Our configs are more complex this time too - we need to add our new Todo to a connection, so we use RANGE_ADD mutation config. Relay expects an edge to be passed in payload, not just a Todo, Reindex provides changedTodoEdge for this. Lastly we need to fetch updated connection count from the server and for this viewer field is available for every payload.

In our optimistic update we increment the count of allTodos, so that we change our “total” display without any delay.

Upvotes: 0

Related Questions