Relay QueryRenderer fragmentContainer passed props different from server response because id conflict

481 Views Asked by At

I'm having this weird issue, basically:

  1. graphql request made from QueryRenderer
  2. Response comes back from the server contains data (inspected from Network tab in dev tools)
  3. props populated in QueryRenderer render({ error, props }) function
  4. the props get passed down into child component with createFragmentContainer which renders the value
  5. The rendered value for one field is different from the response

I'm not sure what relay is doing when it is looking up the data from its own store, but I suspect it is because missing id declaration in a type, here is the code examples:

App.js

<QueryRenderer
  environment={env}
  query={graphql`
    query ScoreboardContainerQuery($ID: ID!) {
      scoreboard(id: $ID) {
        ...Scoreboard_scoreboard
      }
    }
  `}
  variables={{ID: gameID}}

  render={({ error, props }) => {
    return <Scoreboard scoreboard={props ? props.scoreboard : undefined} />
  }}
/>

Scoreboard.js

const Scoreboard = ({ scoreboard }) => (
  <main>
    {scoreboard.matches.map(match => <Match key={match.id} match={match} />)}
  </main>
)

export default createFragmentContainer(Scoreboard, {
  scoreboard: graphql`
  fragment Scoreboard_scoreboard on FootballScoreboard {
    matches {
      ...Match_match
    }
  }
  `,
})

Match.js

const Match = ({ match }) => (
  <div>
    <div>
      {match.homeTeam.displayName}-
      {match.homeTeam.score}
    </div>
    <div>
      {match.awayTeam.displayName}-
      {match.awayTeam.score}
    </div>
  </div>
)

export default createFragmentContainer(Match, {
  match: graphql`
    fragment Match_match on Match {
      date
      homeTeam { // this is a Team type
        id
        displayName
        score
      }
      awayTeam { // this is a Team type
        id
        displayName
        score
      }
    }
  `,
})

sample response for matches from server:

matches = [
  {
    "date": "2017-09-03T06:00:00Z",
    "homeTeam": {
      "id": "330",
      "displayName": "STG",
      "score": "20"
    },
    "awayTeam": {
      "id": "332",
      "displayName": "CBY",
      "score": "0"
    }
  },
  {
    "date": "2017-08-27T06:00:00Z",
    "homeTeam": {
      "id": "329",
      "displayName": "PEN",
      "score": "14"
    },
    "awayTeam": {
      "id": "330",
      "displayName": "STG",
      "score": "0"
    }
  },
  {
    "date": "2017-08-12T05:00:00Z",
    "homeTeam": {
      "id": "330",
      "displayName": "STG",
      "score": "42"
    },
    "awayTeam": {
      "id": "337",
      "displayName": "GCT",
      "score": "0"
    }
  },
]

the rendered value:

(
  <main>
    <div>
      <div>STG-42</div>
      <div>CBY-6</div>
    </div>
    <div>
      <div>PEN-0</div>
      <div>STG-42</div>
    </div>
    <div>
      <div>STG-42</div>
      <div>GCT-18</div>
    </div>
  </main>
)

So all STG value is overridden to 42, and it shouldn't be.

Is this issue caused because there is no id in the Match type which the response is an array? and that's why relay is looking for the Team with same id?

1

There are 1 best solutions below

2
On

This is happening because Relay updates the Team type of id 330 (which is SGT), with the latest value each time ; and the last one of the list is 42.

You could remove the score field from the Team (it does seem a little bit odd, a team doesn't have one score ; it is within a match that she has a score), and create 2 fields on the Match type: awayTeamScore and homeTeamScore.