Search code examples
graphqlrelayjsgraphql-js

fetching additional information for a particular list item in relay/graphql


Using Relay and GraphQL, let's say that I have a schema that returns a viewer, and an embedded list of associated documents. The root query (composed with fragments) would look like something like this:

query Root {
  viewer {
    id,
    name,
    groups {
      edges {
        node {
          id,
          name,
        }
      }
    }
  }
}

This will allow me to display the user, and a list of all of its associated groups.

Now let's say that I want the user to be able to click on that list item, and have it expand to show the comments associated with that particular list item. How should I restructure my query for the relay route such that I can receive those comments? If I add a comments edge to my groups edge, then won't it fetch the comments for all of the groups?

query Root {
  viewer {
    id,
    name,
    groups {
      edges {
        node {
          id,
          name,
          comments {
            edges {
              node {
                id,
                content
              }
            }
          }
        }
      }
    }
  }
}

Or should I alter the route query to find a specific group?

query Root {
  group(id: "someid"){
    id,
    name,
    comments {
      edges {
        node {
          id,
          content
        }
      }
    }
  },
  viewer {
    id,
    name,
    groups {
      edges {
        node {
          id,
          name,
        }
      }
    }
  }
}

My concern is, in particular, using this within the context of relay. I.e., how can I efficiently construct a route query that will only fetch the comments for the expanded list item (or items), while still taking advantage of the cached data that already exists, and will be updated when doing mutations? The above example might work for a specific expanded group, but I'm not sure how I could expand multiple groups simultaneously without fetching those fields for all of the group items.


Solution

  • Relay 0.3.2 will support the @skip and @include directives.

    Group = Relay.createContainer(Group, {
      initialVariables: {
        numCommentsToShow: 10,
        showComments: false,
      },
      fragments: {
        group: () => Relay.QL`
          fragment on Group {
            comments(first: $numCommentsToShow) @include(if: $showComments) {
              edges {
                node {
                  content,
                  id,
                },
              },
            },
            id,
            name,
          }
        `,
      },
    });
    

    In your render method, only render comments if this.props.group.comments is defined. Invoke this.props.relay.setVariables({showComments: true}) in the Group component to cause the comments field to be included (and fetched, if necessary).

    class Group extends React.Component {
      _handleShowCommentsClick() {
        this.props.relay.setVariables({showComments: true});
      }
      renderComments() {
        return this.props.group.comments
          ? <Comments comments={this.props.group.comments} />
          : <button onClick={this._handleShowCommentsClick}>Show comments</button>;
      }
      render() {
        return (
          <div>
            ...
            {this.renderComments()}
          </div>
        );  
      }
    }