Fragments and queries in Relay Modern

Today I want to cover two points: how to use fragments in relay modern and one of the ways of handling routing and relay. Let’s get started!

Fragments

From a previous blog post I have my main page with all films titles. Right now I want to make sure that data I want to fetch is defined in my component. What does it mean? Previously I had a query:

const AppQuery = graphql`
  query AppQuery {
    films {
      id
      title
    }
  }
`;

Which then was used in App.jsx:

<QueryRenderer query={AppQuery} />

But I want to fetch title of my films in FilmList component. To do that I will use a feature called fragments. First I will have my AppQuery:

const AppQuery = graphql`
  query AppQuery {
    films {
      ...FilmList_films
    }
  }
`;

This ... indicates that I’m working here with fragments. In my FilmList component now I can write:

class FilmList extends React.Component {
  render() {
    // some render method
    );
  }
}

export default createFragmentContainer(FilmList, {
  films: graphql`
    fragment FilmList_films on Film @relay(plural: true) {
      id
      title
    }
  `
});

The naming of the fragment is important: first comes a name of a component then after _ prop name to be injected. I also need indication @relay(plural: true) that this fragment will return multiple values.

What are benefits of such approach? I do not need to get all data in the beginning - I fetch it when I need.

Fragments and routing

In above example, I have my FilmList component which has inside link to one instance of given film. How can I create a fragment to get only for this one film? I tried fragment approach with react-router-dom but I have no luck. Relay docs explain that I can’t expect routing to be provided by Relay.

What I do instead (and in such simple case is recommended) I added my own QueryRenderer which renders Film representational component. My relay queries are defined inside FilmContainer:

const FilmQuery = graphql`
  query FilmContainerQuery($filmID: ID!) {
    film(id: $filmID) {
      airDate
      title
      rating
      actors {
        id
        firstName
        lastName
      }
    }
  }
`;

export default class FilmContainer extends Component {
  render() {
    return (
      <QueryRenderer
        environment={environment}
        query={FilmQuery}
        variables={{
          filmID: this.props.match.params.filmId,
        }}
        render={({ error, props }) => {
          if (error) {
            return <div>{error.message}</div>;
          } else if (props) {
            return <Film film={props.film} />;
          }
          return <div>Loading</div>;
        }}
      />
    );
  }
}

In my query, I want to have data only for a particular film so I pass its id as a variable from react-router-dom match. The rest is exactly the same as in AppQuery.

That’s all for today! I hope this post was valuable - if you have any other patterns for React & Relay please let me know! The last thing in your application is to get mutations working which I will take care in the next blog post.

Repo with code can be found on github.