0

Assume I have a field called country defined at the top level of my GraphQL schema. I can query it in the following way:

query {
  country(alpha2: "gb") {
    name
  }
}

In my relay container I can specify the attributes that I would like returned with a fragment on Country:

export default Relay.createContainer(CountryComponent, {
  fragments: {
    country: () => Relay.QL`
      fragment on Country {
        name
      }
    `
  }
}

How can I change the value of the alpha2 argument from within my react component? I could nest the country field under some arbitrary field and declare my relay fragment on the parent but would rather avoid unnecessarily modifying my graph if possible.

Peter Horne
  • 4,588
  • 5
  • 30
  • 48

1 Answers1

1

Generally, we think about top-level parameters like this as being params on the route. Think of them as props that flow into the root of a React app.

If I wanted to redraw a React app with new props, I would simply render it again with the new prop:

ReactDOM.render(<App countryCode="gb" />, …);
// …time passes; country changes
ReactDOM.render(<App countryCode="ca" />, …);

If the country code were a Relay.Route param:

class CountryRoute extends Relay.Route {
  static queries = {
    country: () => Relay.QL`
      query { country(alpha2: $countryCode) }
    `,
  };
  static paramDefinitions = {
    countryCode: {required: true},
  };
  static routeName = 'CountryRoute';
}

I could do something similar:

ReactDOM.render(
  <Relay.RootContainer 
    Component={CountryComponent}
    route={new CountryRoute({countryCode: 'gb'})}
  />,
  …
);
// …time passes; country changes
ReactDOM.render(
  <Relay.RootContainer 
    Component={CountryComponent}
    route={new CountryRoute({countryCode: 'ca'})}
  />,
  …
);

As for how and when to re-render with new route params, you could trigger a custom event from your React component with an associated listener that causes ReactDOM.render to be called again, but since you're using react-router-relay, you might consider simply changing the country code in the URL and letting it re-trigger the route with the new countryCode param.

See also: http://facebook.github.io/relay/docs/guides-routes.html#routes-and-queries

steveluscher
  • 3,901
  • 20
  • 41
  • Thanks. In my situation the change is triggered by a user selecting their country while filling out a form (in order to fetch the corresponding time zones) so changing the URL is undesirable here. Perhaps I'm thinking about this wrong, maybe only 'parent' type fields should be exposed at the top level, such as `User`? It just seems strange to nest `Country` as it doesn't belong to any parent type? – Peter Horne Oct 30 '15 at 10:26
  • That sounds fine! You can change the URL in response to a new choice of country (just add it as a query param via `history.replaceState()`, and have the router render the root container anew) or you can simply have a top level listener to which you broadcast changes to the country – a listener that re-renders the app in response to the change. Without knowing more about your app, it's hard for me to give a more specific recommendation than those two. – steveluscher Nov 02 '15 at 06:43