Relay: Cannot have duplicate variables name in props and fragments with different values

Created on 3 Aug 2016  路  1Comment  路  Source: facebook/relay

Based on the validation implemented in https://github.com/facebook/relay/commit/b22c3eab7fe56789fe6ba335bb862bf323f47b2e :

it difficult to debug when the variables used in a fragment - Child.getFragment('foo', {size: 32}) - does not match the variables passed as props: <Child ... size={64} />

I'm not sure if I understand the reason for this validation correctly. Normally, the prop passed to <Child ... size={64} /> is not related to the variable used in fragment, the variable in the fragment must be set by using this.props.relay.setVariable({size: 32}), initialVariables, or prepareVariables. So, both of them are not related at all, are they?

This validation gives the warning when the name of prop in containers and the name of variable in fragments are the same but different values. Here is a scenario when this introduces problem:

//  Child Component
componentWillMount() {
    // Assume the data is big and we want to fetch data only if the component needed to be rendered, 
    this.props.relay.setVariables({  userId: this.props.userId, size: 32, hasQuery: true });
  }
// Child Container
export default Relay.createContainer(ChildComponent, {
  initialVariables: {
    userId: null,
    size: null,
    hasQuery: false
  },
  fragments: {
    viewer: () => Relay.QL`
      fragment on Viewer {
        getPosts(userId: $userId, size: $size) @include(if: $hasQuery) {
        ...
   }
}
// Parent Component
<Child userId={1} />

This will definitely give the warning as following:

warning.js:44 Warning: RelayContainer: component `Child` was rendered with variables that differ from the variables used to fetch fragment `viewer`. The fragment was fetched with variables `{"userId":null,"size":null,"hasQuery":false}`, but rendered with variables `{"userId" 1, "size":null,"hasQuery":false}`

Could you provide the scenario that the validation is useful? What's the proper way to get rid of the warning in my scenario, I could just name them differently but might be some better approach?

legacy-core-api question

Most helpful comment

Thanks for bringing this up.

It may not be possible to suppress the warning in all cases, as there are some known false positives that come up. Relay 2 completely changes the way variables are modeled and handled in the system, so this particular class of problem will go away. Until then, you may just have to ignore the warnings. As such, I'm going to label this one with the "relay 1" label and mark it as closed.

To answer your question about when the validation is useful, it has eliminated for us a large class of bugs where people fetch a fragment with a particular set of variables, but then forget to pass those same variables in at render time. Passing it in is necessary because of the two-phase process in which fragments are used: in the first phase Relay must be able to traverse the component hierarchy without actually instantiating any components so that it can statically construct the query to be sent to the server to fetch the data; in the second phase the data has arrived and Relay actually renders, but it can't automatically know what variables to pass to the component at render time because each component may be instantiated an arbitrary number of times by a parent, each with different variables.

(Tangentially: why are you using componentWillMount instead of componentDidMount? Conceptually, the latter is a better fit for the render-initial-then-render-more lifecycle that you are implementing here.)

>All comments

Thanks for bringing this up.

It may not be possible to suppress the warning in all cases, as there are some known false positives that come up. Relay 2 completely changes the way variables are modeled and handled in the system, so this particular class of problem will go away. Until then, you may just have to ignore the warnings. As such, I'm going to label this one with the "relay 1" label and mark it as closed.

To answer your question about when the validation is useful, it has eliminated for us a large class of bugs where people fetch a fragment with a particular set of variables, but then forget to pass those same variables in at render time. Passing it in is necessary because of the two-phase process in which fragments are used: in the first phase Relay must be able to traverse the component hierarchy without actually instantiating any components so that it can statically construct the query to be sent to the server to fetch the data; in the second phase the data has arrived and Relay actually renders, but it can't automatically know what variables to pass to the component at render time because each component may be instantiated an arbitrary number of times by a parent, each with different variables.

(Tangentially: why are you using componentWillMount instead of componentDidMount? Conceptually, the latter is a better fit for the render-initial-then-render-more lifecycle that you are implementing here.)

Was this page helpful?
0 / 5 - 0 ratings