Solo Solo - 1 month ago 14
React JSX Question

Fetch additional data for a single item in a list query

Im trying to do something like this with React and Relay - smooth animation from list to single item.

I currently have list component (list query) and single item component (node query) but there's a problem: these are two different, isolated views and queries, I can't think of an easy way to smootly animate between these two views.




Easiest way would probably be to transform / scale that same list item:



React part is simple, I'll calculate screen size on click and transform the list item to full-screen size.




How about data? Is something like this possible with Relay? Can I fetch more data for single item in list query or could I use node query in same component, a'la use two queries per component?




// Simple list query example

export default Relay.createContainer(PostList, {
initialVariables: {
count: 10
},
fragments: {
viewer: () => Relay.QL`
fragment on Viewer {
posts(first: $count) {
edges {
node {
id
title
}
}
}
}`
}
})

// What if I needed to fetch "content" for a single item as well?

Answer

Yes, you can fetch multiple fragments per component. My suggestion here would be to have a separate fragment for the selected post, and to make use of it in a route dedicated for the post's detail (permalink) view.

First, add a fragment to represent the selected post.

export default Relay.createContainer(PostList, {
  initialVariables: {
    count: 10,
  },
  fragments: {
    selectedPost: () => Relay.QL`
      fragment on Post {
        id
        title
        description
      }
    `,
    viewer: () => Relay.QL`
      fragment on Viewer {
        posts(first: $count) {
          edges {
            node {
              id
              title
            }
          }
        }
      }
    `,
  },
});

Then create two routes. One will represent only the index view's queries, and one the permalink view's queries.

class IndexRoute extends Relay.Route {
  static queries = {
    viewer: () => Relay.QL`query { viewer }`,
  };
  static routeName = 'IndexRoute';
}

class PostPermalinkRoute extends Relay.Route {
  static queries = {
    selectedPost: () => Relay.QL`query { node(id: $postID) }`,
    viewer: () => Relay.QL`query { viewer }`,
  };
  static paramDefinitions = {
    // By setting `required` to true, `PostPermalinkRoute` 
    // will throw if a `postID` is not supplied when instantiated.
    postID: {required: true},
  };
  static routeName = 'PostPermalinkRoute';
}

Now, you need to write some code that rerenders the app with a new route when you want to switch between the index and the permalink views. By default, Relay will keep rendering the old route while the data for the next route loads, so you should be able to perform your transitions while you wait on the data.

function render(route) {
  ReactDOM.render(
    <Relay.RootContainer
      Component={PostList}
      route={route}
    />,
    container,
  );
}

// When it's time to render the index...
render(new IndexRoute());

// Upon selecting a post...
render(new PostPermalinkRoute({postID: 123}));

The current route is available to you as this.props.relay.route, so you should be able to make some inferences about what state you should be in using this.props.relay.route.name and this.props.relay.route.params.