How to combine FragmentContainer with RefetchContainer in Relay modern

382 Views Asked by At

I'm migrating some Relay classis code to Relay modern. And now I'm having a hard time migrating a pagination implementation. I'm using a page and offset approach. Here's what I have now:

Game.jsx:

import React from 'react';
import ReactDOM from 'react-dom';
import {QueryRenderer, createFragmentContainer, createRefetchContainer, graphql} from 'react-relay';
import Player from './Player';

class Game extends React.Component {
    _loadPage(e) {
      e.preventDefault();
      this.props.relay.refetch({page: parseInt(e.target.dataset.page)}, null);
    }

    render() {
        return (
            <div>
                <h1>{this.props.game.name}</h1>
                <ul className="pagination">
                    {this.props.game.pages.map((page) => {
                        <li key={page.page}>
                            <a href="#" data-page={page.page} onClick={this._loadPage}>{page.page}</a>
                        </li>
                    })
                </ul>
                {this.props.game.players.map(player =>
                    <Player key={player.id} />
                )}
            </div>
        );
    }   
}

Game = createRefetchContainer(
  Game,
  {
      players: graphql`
        fragment Game_players on Game
        @argumentDefinitions(
          page: {type: "Int", defaultValue: 1},
          first: {type: "Int", defaultValue: 15}
        )
        {
          players(page: $page, first: $first) {
            id
            ...Player_player
          }
        }
    `
  },
  graphql`
    query GamePlayersRefetch_Query($page: Int!, $first: Int!) {
      game(id: $id) {
        ...Game_players @arguments(page: $page, first: $first)
      }
    }
  `
);


Game = createFragmentContainer(
    Game,
    graphql`
        fragment Game_game on Game
          @argumentDefinitions(
            page: {type: "Int", defaultValue: 1},
            first: {type: "Int", defaultValue: 15}
          ) {
          id
          name
          pages {
            page
          }
          ...game_players @arguments(page: $page, first: $first)
        }
    `
)


$(document).on("load turbolinks:load DOMContentLoaded", e => {
    let element = document.getElementById('game');
    ReactDOM.render(
          <QueryRenderer
            environment={environment}
            query={
              graphql`
                query gameQuery(
                    $id: ID!
                    $page: Int!
                    $first: Int!
                ) {
                      game(id: $id) {
                        ...Game_game @arguments(page: $page, first: $first)
                      }
                   }
            `
            }
            variables={{
              id: element.dataset.id,
              page: 1,
              first: 15
            }}
            render={({error, props}) => {
              if (props) {
                return <Game />
              } else {
                return <div>Loading.../div>
              }
            }}
          />,
          element
        );
    }

});

Player.jsx:

import React from 'react';
import {createFragmentContainer, graphql} from 'react-relay';

class Player extends React.Component {
    render() {
        <div className="player">
            <div class="player-name">{this.props.player.name}</div>
        </div>
    }
}


export default createFragmentContainer(
  Player,
  graphql`
    fragment Player_player on Player {
      id
    }
    `
);

I must be doing something wrong with the FragmentContainer and the RefetchContainer they should be combined or something but I don't have a clue how to achieve what I want. Can someone enlighten me?

1

There are 1 best solutions below

0
On

After hours of trial and error I figured it out myself. This always happens when one posts something on StackOverflow...

This is what I had to do:

Game = createRefetchContainer(
  Game,
  {
      game: graphql`
        fragment Game_game on Game
        @argumentDefinitions(
          page: {type: "Int", defaultValue: 1},
          first: {type: "Int", defaultValue: 15}
        )
        {
          id
          name
          players(page: $page, first: $first) {
            id
            ...Player_player
          }
        }
    `
  },
  graphql`
    query GamePlayersRefetch_Query($page: Int!, $first: Int!) {
      game(id: $id) {
        ...Game_players @arguments(page: $page, first: $first)
      }
    }
  `
);

Now no FragmentContainer is needed anymore. Please notice that the name of the fragment is renamed to Game_game.