facebook / relay

Relay is a JavaScript framework for building data-driven React applications.
https://relay.dev
MIT License
18.38k stars 1.82k forks source link

[Bug] - Relay fragment variables #1218

Closed mario-jerkovic closed 7 years ago

mario-jerkovic commented 8 years ago

We have encountered an strange behaviour of Relay. I will try to explain the best I can.

So we have an "main" relay container that fetches the data for corresponding store, and also includes and fragment from Ticket container. Ticket container render out custom table that has filter and sorting. So you can see that in StoreFrom component StoreTicketList container is import all required props are passed like Store fragment.

The problem occurs when you try to filter StoreList Ticket, I mean set filter or sort relay variables. You will get this error:

Warning: RelayContainer: component TicketList was rendered with variables that differ from the variables used to fetch fragment Store. The fragment was fetched with variables {"first":5,"after":null,"last":null,"before":null,"sort":null,"filter":null}, but rendered with variables {"first":5,"after":null,"last":null,"before":null,"sort":null,"filter":{"authorAccount":{"email":{"__e":"wrongEmail@email.com"}}}}. This can indicate one of two possibilities:

But those filter/sort variables are on StoreTicketList and they arent passed dow from parent to child container like in this case Store container to StoreListTicket container.

export class StoreForm extends React.Component {

  constructor(props) {
    super(props);

    const { Viewer: { store } } = props;

    this.state = {
      number: store && store.number !== null ? store.number : '',
    };
  }

  handleInsert = (model) => {
    console.log('Form mutation model : ', model);
  };

  render() {
    const { Viewer, relay: { variables: { update } } } = this.props;
    return (
      <div>
        <Form>
          <FormTitle title='Store Info' />
          <FormBody>
            <TextField
              required
              fullWidth
              name='number'
              value={this.state.number}
              floatingLabelText='Number'
            />
            <StoreTicketList Store={this.props.Viewer.store} />
          </FormBody>
        </Form>
      </div>
    );
  }
}
export default Relay.createContainer(StoreForm, {
  initialVariables: {
    id: null,
    update: false
  },
  prepareVariables({ id = null }) {
    return { id, update: (id !== null) };
  },
    fragments: {
        Viewer: (variables) => Relay.QL`
      fragment on Viewer {
        store(id: $id) @include(if: $update) {
          id,
          number
          ${StoreTIcketList.getFragment('Store')}
        }
      }
    `
    }
});

Ticket Container:

export const StoreTicketList = Relay.createContainer(TicketList, {
  initialVariables: {
    first: 5,
    after: null,
    last: null,
    before: null,
    sort: null,
    filter: null
  },
    fragments: {
        Store: () => Relay.QL`
      fragment on Store {
        ticketConnection(first: $first, after: $after, last: $last, before: $before, sort: $sort, filter: $filter) {
          count,
          pageInfo {
            hasNextPage,
            hasPreviousPage,
            startCursor,
            endCursor
          },
          edges{
            node{
              created,
              subject
            }
          }
        }
      }
    `
    }
});
josephsavona commented 8 years ago

Thanks for your question! I have an answer for you, but we'd prefer to answer this in a forum that is easily searchable by other members of the community who have a similar question. Would you like to post this question to Stack Overflow with the tag #relayjs? We'll be happy to answer there. Please post a link to your Stack Overflow question here, to so that we don't lose track of it. Thanks!

https://stackoverflow.com/questions/ask?tags=relayjs

mario-jerkovic commented 8 years ago

No problem, here is the Stack Overflow question.

http://stackoverflow.com/questions/37866342/relay-fragment-variables

mario-jerkovic commented 8 years ago

I have tried to isolate the problem, and have created small example of the models on GraphQL side and Containers/Components on the frontend side.

Here is the repo link: https://github.com/mario-jerkovic/Relay-FragmentVariables

If you uncomment the code inside/js/routes/AppHomeRoute.js and/js/app.js, relay wont complaint about different variables, the only difference between working and not working code the the react-router-relay.

skosch commented 8 years ago

Ha, I just ran into the same problem. The error message could be more helpful. It turns out you need to do two things:

<Route path="interviews">
  <IndexRoute component={InterviewsList} queries={ViewerQuery} />
  <Route path=":id" component={InterviewSession} queries={NodeViewerQuery}
              render={({ props }) => props ? <InterviewSession {...props} /> : <Loading />}/> // <--- this line
</Route>
    fragments: {
        Viewer: (variables) => Relay.QL`
      fragment on Viewer {
        store(id: $id) @include(if: $update) {
          id,
          number
          ${StoreTIcketList.getFragment('Store', {... variables})} // <---- this thing!
        }
      }
    `
    }

For me the problem was in the root query, where it looks instead like:

const NodeViewerQuery = {
  node: (component, variables) => Relay.QL`query { // <---- extra "component" argument
    node(id: $id) {
      ${component.getFragment('node', {...variables})}
    }
  }`,

I haven't looked at your repo, but maybe this helps you out. To the Relay folks, it'd be nice if this error message pointed to a dedicated example page, or at least explicitly mentioned all the places variables need to be passed in.

josephsavona commented 8 years ago

@skosch Thanks for answering. Would you mind including your answer at Stack Overflow as well to help the community find this answer?

We're definitely aware that this is tricky, and we're looking at ways to simplify passing variables. We'll see how this goes and consider documenting the current system more in the meantime.

skosch commented 8 years ago

Done, thanks :)

mario-jerkovic commented 8 years ago

@josephsavona I have added those changes @skosch proposed and i have the same thing/problem ... You can take a look at my repo from last post... I dont see why passing variables from parent to child container should work, beacuse they are using different set of initial variables to render the container.. Store container has only id but ticket container has filter, first, last, after and before. so those are tied to ticket container.

initially ticket container is renderd with filter: null the you update it with:

relay.setVariables({
      filter: {
        subject: !relay.variables.filter ? { __e: 'something' } : { __ne: 'else' }
      }
    })

on second render when filter is this.props.relay.variables.filter = { subject: { __e: 'something' } relay dosen't complain but when you update the filter variable second time it is.

skosch commented 8 years ago

I suspect (being on mobile and unable to test it) that the problem is <StoreListTickets store={this.props.viewer.store} /> -- try to pass those variables as props to that component?

josephsavona commented 8 years ago

The problem appears to be in StoreForm - StoreForm is not passing variables to StoreTicketList as props. You should be able to fix this by either:

I would also highly recommend trying this on Relay master - we added some refinements to this warning and I'm not sure if they made the cut for the last release. I have a feeling that doing option 1 above plus upgrading to master will fix this warning.

mario-jerkovic commented 8 years ago

Sorry for the late response.

I have tried both solutions, and also updated relay to master branch, and sadly none of them worked, getting the same error message...I mean if that is an issue with relay then ok, probably it's solvable, it's just annoying to see that error message

jardakotesovec commented 8 years ago

Also getting this warning in scenario where I use only initialVariables and setVariables within one component to fetch data on demand and I don't pass any variables via fragments.

Is @mario-jerkovic repro case enough to identify the issue or should I provide more details?

skosch commented 8 years ago

I did get a chance to look at @mario-jerkovic's repo and while I didn't have a chance to take a closer look at it (let alone find a solution) I did confirm that my original suggestion didn't help, because the issue is caused by setVariables (unlike mine, which wasn't). Sorry!

@jardakotesovec sounds like you've come exactly to the right place – hopefully someone can help you guys out!

josephsavona commented 8 years ago

@jardakotesovec Do you have an isolated repro that would help us debug?

jardakotesovec commented 8 years ago

@josephsavona Nope.. but I can attempt to create repro in relay playground tomorrow if that would help.

josephsavona commented 8 years ago

@jardakotesovec That would be super helpful in diagnosing this.

mario-jerkovic commented 8 years ago

@josephsavona I will recreate my repo in playground if the repo by itself wasent helpful

josephsavona commented 8 years ago

@mario-jerkovic I looked at the repo to try diagnose, but it would definitely be much easier for us to run and debug if you can repro in the Relay playground.

mario-jerkovic commented 8 years ago

@josephsavona Here is the Relay Playground link (sorry for just copy and pasting, I have tried to use many link shortners but it always says that it's invalid :smile: )

https://facebook.github.io/relay/prototyping/playground.html#source=%0Aclass%20TicketList%20extends%20React.Component%20%7B%0A%20%20constructor(props)%20%7B%0A%20%20%20%20super(props)%3B%0A%20%20%7D%0A%0A%20%20filterHandler%20%3D%20()%20%3D%3E%20%7B%0A%20%20%20%20const%20%7Brelay%7D%20%3D%20this.props%3B%0A%0A%20%20%20%20relay.setVariables(%7B%0A%20%20%20%20%20%20filter%3A%20%7B%0A%20%20%20%20%20%20%20%20subject%3A%20!relay.variables.filter%20%3F%20%7B%20__e%3A%20'something'%20%7D%20%3A%20%7B%20__ne%3A%20'else'%20%7D%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D)%0A%20%20%7D%3B%0A%0A%20%20render()%20%7B%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%3Cdiv%3E%0A%20%20%20%20%20%20%20%20%3Ch1%3ETickets%3C%2Fh1%3E%0A%20%20%20%20%20%20%20%20%3Cbutton%20onClick%3D%7Bthis.filterHandler%7D%3EChange%20filter%3C%2Fbutton%3E%0A%20%20%20%20%20%20%20%20%3Cdiv%3E%7B%60Active%20filters%3A%20%24%7BJSON.stringify(this.props.relay.variables.filter%2C%20null%2C%202)%7D%60%7D%3C%2Fdiv%3E%0A%20%20%20%20%20%20%20%20%3Cul%3E%0A%20%20%20%20%20%20%20%20%20%20%7Bthis.props.store.ticketConnection.edges.map(edge%20%3D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cli%20key%3D%7Bedge.node.id%7D%3E%7Bedge.node.title%20%2B%20'%20'%20%2B%20edge.node.subject%7D%20(ID%3A%20%7Bedge.node.id%7D)%3C%2Fli%3E%0A%20%20%20%20%20%20%20%20%20%20)%7D%0A%20%20%20%20%20%20%20%20%3C%2Ful%3E%0A%20%20%20%20%20%20%3C%2Fdiv%3E%0A%20%20%20%20)%3B%0A%20%20%7D%0A%7D%0A%0Aconst%20StoreListTickets%20%3D%20Relay.createContainer(TicketList%2C%20%7B%0A%20%20initialVariables%3A%20%7B%0A%20%20%20%20first%3A%205%2C%0A%20%20%20%20after%3A%20null%2C%0A%20%20%20%20last%3A%20null%2C%0A%20%20%20%20before%3A%20null%2C%0A%20%20%20%20filter%3A%20null%0A%20%20%7D%2C%0A%20%20fragments%3A%20%7B%0A%20%20%20%20store%3A%20(variables)%20%3D%3E%20Relay.QL%60%0A%20%20%20%20%20%20fragment%20on%20Store%20%7B%0A%20%20%20%20%20%20%20%20ticketConnection(first%3A%20%24first%2C%20last%3A%20%24last%2C%20before%3A%20%24before%2C%20after%3A%20%24after%2C%20filter%3A%20%24filter%20)%20%7B%0A%20%20%20%20%20%20%20%20%20%20edges%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20node%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20id%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20title%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20subject%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%60%0A%20%20%7D%0A%7D)%3B%0A%0Aclass%20StoreForm%20extends%20React.Component%20%7B%0A%20%20%0A%20%20constructor(props)%20%7B%0A%20%20%20%20super(props)%3B%0A%20%20%20%20this.state%20%3D%20%7B%0A%20%20%20%20%20%20clickMe%3A%20false%0A%20%20%20%20%7D%0A%20%20%7D%0A%20%20%0A%20%20render()%20%7B%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%3Cdiv%3E%0A%20%20%20%20%20%20%20%20%3Cbutton%20onClick%3D%7B()%20%3D%3E%20%7Bthis.setState(%7B%20clickMe%3A%20!this.state.clickMe%20%7D)%7D%7D%3E%0A%20%20%20%20%20%20%20%20%20%20First%20click%20%22change%20filter%22%20than%20ME%20%3A)%0A%20%20%20%20%20%20%20%20%3C%2Fbutton%3E%0A%20%20%20%20%20%20%20%20%3Ch1%3EStore%20-%20tickets%3C%2Fh1%3E%0A%20%20%20%20%20%20%20%20%3Cdiv%3E%7Bthis.props.viewer.store.name%7D%20(ID%3A%20%7Bthis.props.viewer.store.id%7D)%3C%2Fdiv%3E%0A%20%20%20%20%20%20%20%20%3CStoreListTickets%20store%3D%7Bthis.props.viewer.store%7D%20%2F%3E%0A%20%20%20%20%20%20%3C%2Fdiv%3E%0A%20%20%20%20)%3B%0A%20%20%7D%0A%7D%0A%0Aconst%20App%20%3D%20Relay.createContainer(StoreForm%2C%20%7B%0A%20%20initialVariables%3A%20%7B%0A%20%20%20%20id%3A%20%22c3RvcmU6MQ%3D%3D%22%0A%20%20%7D%2C%0A%20%20fragments%3A%20%7B%0A%20%20%20%20viewer%3A%20(variables)%20%3D%3E%20Relay.QL%60%0A%20%20%20%20%20%20fragment%20on%20Viewer%20%7B%0A%20%20%20%20%20%20%20%20store(id%3A%20%24id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20id%2C%0A%20%20%20%20%20%20%20%20%20%20name%2C%0A%20%20%20%20%20%20%20%20%20%20%24%7BStoreListTickets.getFragment('store')%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%60%0A%20%20%7D%0A%7D)%3B%0A%0Aclass%20AppHomeRoute%20extends%20Relay.Route%20%7B%0A%20%20static%20routeName%20%3D%20'AppHomeRoute'%3B%0A%20%20%0A%20%20static%20queries%20%3D%20%7B%0A%20%20%20%20viewer%3A%20()%20%3D%3E%20Relay.QL%60%0A%20%20%20%20%20%20query%20%7B%0A%20%20%20%20%20%20%20%20viewer%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%60%2C%0A%20%20%7D%3B%0A%7D%0A%0AReactDOM.render(%0A%20%20%3CRelay.RootContainer%0A%20%20%20%20Component%3D%7BApp%7D%0A%20%20%20%20route%3D%7Bnew%20AppHomeRoute()%7D%0A%20%20%2F%3E%2C%0A%20%20mountNode%0A)%3B%0A&schema=import%20%7B%0A%20%20GraphQLID%2C%0A%20%20GraphQLInt%2C%0A%20%20GraphQLObjectType%2C%0A%20%20GraphQLSchema%2C%0A%20%20GraphQLString%2C%0A%20%20GraphQLInputObjectType%0A%7D%20from%20'graphql'%3B%0A%0Aimport%20%7B%0A%20%20connectionArgs%2C%0A%20%20connectionDefinitions%2C%0A%20%20connectionFromArray%2C%0A%20%20fromGlobalId%2C%0A%20%20globalIdField%2C%0A%20%20nodeDefinitions%2C%0A%7D%20from%20'graphql-relay'%3B%0A%0A%2F%2F%20Model%20types%0Aclass%20Root%20%7B%7D%0Aclass%20Store%20%7B%7D%0Aclass%20Ticket%20%7B%7D%0A%0A%2F%2F%20Mock%20data%0Aconst%20viewer%20%3D%20new%20Root()%3B%0A%20%20%20%20%20%20viewer.id%20%3D%20'1'%3B%0A%20%20%20%20%20%20viewer.name%20%3D%20'Anonymous'%3B%0A%0Aconst%20stores%20%3D%20%5B%0A%20%20%7B%20name%3A%20'Store-1'%2C%20ticket%3A%20%5B1%2C2%2C3%5D%20%7D%2C%0A%20%20%7B%20name%3A%20'Store-2'%2C%20ticket%3A%20%5B2%2C4%2C3%5D%20%7D%2C%0A%20%20%7B%20name%3A%20'Store-3'%2C%20ticket%3A%20%5B2%2C%205%5D%20%7D%0A%5D.map((%7B%20name%2C%20ticket%20%7D%2C%20i)%20%3D%3E%20%7B%0A%20%20const%20a%20%3D%20new%20Store()%3B%0A%0A%20%20a.name%20%3D%20name%3B%0A%20%20a.ticket%20%3D%20ticket%3B%0A%20%20a.number%20%3D%20i%3B%0A%20%20a.id%20%3D%20%60%24%7Bi%7D%60%3B%0A%0A%20%20return%20a%3B%0A%7D)%3B%0A%0Aconst%20tickets%20%3D%20%5B%0A%20%20%7B%20title%3A%20'Test-1'%2C%20subject%3A%20'Subject-1'%20%7D%2C%0A%20%20%7B%20title%3A%20'Test-2'%2C%20subject%3A%20'Subject-2'%20%7D%2C%0A%20%20%7B%20title%3A%20'Test-3'%2C%20subject%3A%20'Subject-3'%20%7D%2C%0A%20%20%7B%20title%3A%20'Test-4'%2C%20subject%3A%20'Subject-4'%20%7D%2C%0A%20%20%7B%20title%3A%20'Test-5'%2C%20subject%3A%20'Subject-5'%20%7D%2C%0A%20%20%7B%20title%3A%20'Test-6'%2C%20subject%3A%20'Subject-6'%20%7D%0A%5D.map((%7B%20title%2C%20subject%20%7D%2C%20i)%20%3D%3E%20%7B%0A%20%20const%20a%20%3D%20new%20Ticket()%3B%0A%0A%20%20a.title%20%3D%20title%3B%0A%20%20a.subject%20%3D%20subject%3B%0A%20%20a.id%20%3D%20%60%24%7Bi%7D%60%3B%0A%0A%20%20return%20a%3B%0A%7D)%3B%0A%0Aconst%20exportObject%3D%20%7B%0A%20%20getRoot%3A%20(id)%20%3D%3E%20id%20%3D%3D%3D%20viewer.id%20%3F%20viewer%20%3A%20null%2C%0A%20%20getViewer%3A%20()%20%3D%3E%20viewer%2C%0A%20%20getStore%3A%20(id)%20%3D%3E%20stores.find(w%20%3D%3E%20w.id%20%3D%3D%3D%20id)%2C%0A%20%20getStores%3A%20()%20%3D%3E%20stores%2C%0A%20%20getConnectedTickets%3A%20(array)%20%3D%3E%20(array.map(id%20%3D%3E%20(tickets.find(w%20%3D%3E%20parseInt(w.id)%20%3D%3D%3D%20id))))%2C%0A%20%20getTicket%3A%20(id)%20%3D%3E%20tickets.find(w%20%3D%3E%20w.id%20%3D%3D%3D%20id)%2C%0A%20%20getTickets%3A%20()%20%3D%3E%20tickets%2C%0A%20%20Root%2C%0A%20%20Store%2C%0A%20%20Ticket%0A%7D%3B%0A%0Aconst%20%7BnodeInterface%2C%20nodeField%7D%20%3D%20nodeDefinitions(%0A%20%20(globalId)%20%3D%3E%20%7B%0A%20%20%20%20const%20%7Btype%2C%20id%7D%20%3D%20fromGlobalId(globalId)%3B%0A%20%20%20%20if%20(type%20%3D%3D%3D%20'Viewer')%20%7B%0A%20%20%20%20%20%20return%20exportObject.getRoot(id)%3B%0A%20%20%20%20%7D%20else%20if%20(type%20%3D%3D%3D%20'store')%20%7B%0A%20%20%20%20%20%20return%20exportObject.getStore(id)%3B%0A%20%20%20%20%7D%20else%20if%20(type%20%3D%3D%3D%20'ticket')%20%7B%0A%20%20%20%20%20%20return%20exportObject.getTicket(id)%3B%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20return%20null%3B%0A%20%20%20%20%7D%0A%20%20%7D%2C%0A%20%20(obj)%20%3D%3E%20%7B%0A%20%20%20%20if%20(obj%20instanceof%20exportObject.Root)%20%7B%0A%20%20%20%20%20%20return%20viewerType%3B%0A%20%20%20%20%7D%20else%20if%20(obj%20instanceof%20exportObject.Store)%20%20%7B%0A%20%20%20%20%20%20return%20storeType%3B%0A%20%20%20%20%7D%20else%20if%20(obj%20instanceof%20exportObject.Ticket)%20%20%7B%0A%20%20%20%20%20%20return%20ticketType%3B%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20return%20null%3B%0A%20%20%20%20%7D%0A%20%20%7D%0A)%3B%0A%0Aconst%20ticketType%20%3D%20new%20GraphQLObjectType(%7B%0A%20%20name%3A%20'Ticket'%2C%0A%20%20fields%3A%20()%20%3D%3E%20(%7B%0A%20%20%20%20id%3A%20globalIdField('ticket'%2C%20(%7B%20id%20%7D)%20%3D%3E%20id)%2C%0A%20%20%20%20title%3A%20%7B%0A%20%20%20%20%20%20type%3A%20GraphQLString%2C%0A%20%20%20%20%20%20resolve%3A%20(%7B%20title%20%7D)%20%3D%3E%20title%0A%20%20%20%20%7D%2C%0A%20%20%20%20subject%3A%20%7B%0A%20%20%20%20%20%20type%3A%20GraphQLString%2C%0A%20%20%20%20%20%20resolve%3A%20(%7B%20subject%20%7D)%20%3D%3E%20subject%0A%20%20%20%20%7D%0A%20%20%7D)%2C%0A%20%20interfaces%3A%20()%20%3D%3E%20%5BnodeInterface%5D%0A%7D)%3B%0A%0Aconst%20%7B%20connectionType%3A%20ticketConnection%2C%20edgeType%20%3A%20graphQLTicketEdge%2C%20%7D%20%3D%20connectionDefinitions(%7B%20name%3A%20'Ticket'%2C%20nodeType%3A%20ticketType%20%7D)%3B%0A%0Aconst%20FilterObject%20%3D%20new%20GraphQLInputObjectType(%7B%0A%20%20name%3A%20'FilterObject'%2C%0A%20%20fields%3A%20%7B%0A%20%20%20%20__e%3A%20%7B%20type%3A%20GraphQLString%20%7D%2C%0A%20%20%20%20__ne%3A%20%7B%20type%3A%20GraphQLString%20%7D%0A%20%20%7D%0A%7D)%3B%0A%0Aconst%20storeType%20%3D%20new%20GraphQLObjectType(%7B%0A%20%20name%3A%20'Store'%2C%0A%20%20fields%3A%20()%20%3D%3E%20(%7B%0A%20%20%20%20id%3A%20globalIdField('store'%2C%20(%7B%20id%20%7D)%20%3D%3E%20id)%2C%0A%20%20%20%20number%3A%20%7B%0A%20%20%20%20%20%20type%3A%20GraphQLInt%2C%0A%20%20%20%20%20%20resolve%3A%20(%7B%20number%20%7D)%20%3D%3E%20number%0A%20%20%20%20%7D%2C%0A%20%20%20%20name%3A%20%7B%0A%20%20%20%20%20%20type%3A%20GraphQLString%2C%0A%20%20%20%20%20%20resolve%3A%20(%7B%20name%20%7D)%20%3D%3E%20name%0A%20%20%20%20%7D%2C%0A%20%20%20%20ticketConnection%3A%20%7B%0A%20%20%20%20%20%20type%3A%20ticketConnection%2C%0A%20%20%20%20%20%20args%3A%20%7B%0A%20%20%20%20%20%20%20%20filter%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20type%3A%20new%20GraphQLInputObjectType(%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3A%20'Filter'%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20fields%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20title%3A%20%7B%20type%3A%20FilterObject%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20subject%3A%20%7B%20type%3A%20FilterObject%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20...connectionArgs%0A%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20resolve%3A%20(%7B%20ticket%20%7D%2Cargs)%20%3D%3E%20connectionFromArray(exportObject.getConnectedTickets(ticket)%2C%20args)%0A%20%20%20%20%7D%0A%20%20%7D)%2C%0A%20%20interfaces%3A%20()%20%3D%3E%20%5BnodeInterface%5D%0A%7D)%3B%0A%0Aconst%20%7B%20connectionType%3A%20storeConnection%2C%20edgeType%20%3A%20graphQLStoreEdge%2C%20%7D%20%3D%20connectionDefinitions(%7B%20name%3A%20'Store'%2C%20nodeType%3A%20storeType%20%7D)%3B%0A%0Aconst%20viewerType%20%3D%20new%20GraphQLObjectType(%7B%0A%20%20name%3A%20'Viewer'%2C%0A%20%20description%3A%20'Viewer'%2C%0A%20%20fields%3A%20()%20%3D%3E%20(%7B%0A%20%20%20%20id%3A%20globalIdField('Viewer')%2C%0A%20%20%20%20store%3A%20%7B%0A%20%20%20%20%20%20type%3A%20storeType%2C%0A%20%20%20%20%20%20args%3A%20%7B%0A%20%20%20%20%20%20%20%20id%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20type%3A%20GraphQLID%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20resolve%3A%20(_%2C%20%7B%20id%20%7D)%20%3D%3E%20exportObject.getStore(fromGlobalId(id).id)%0A%20%20%20%20%7D%2C%0A%20%20%20%20storeConnection%3A%20%7B%0A%20%20%20%20%20%20type%3A%20storeConnection%2C%0A%20%20%20%20%20%20args%3A%20connectionArgs%2C%0A%20%20%20%20%20%20resolve%3A%20(_%2C%20args)%20%3D%3E%20connectionFromArray(exportObject.getStores()%2C%20args)%0A%20%20%20%20%7D%2C%0A%20%20%20%20ticket%3A%20%7B%0A%20%20%20%20%20%20type%3A%20ticketType%2C%0A%20%20%20%20%20%20args%3A%20%7B%0A%20%20%20%20%20%20%20%20id%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20type%3A%20GraphQLID%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20resolve%3A%20(_%2C%20%7B%20id%20%7D)%20%3D%3E%20exportObject.getTicket(fromGlobalId(id).id)%0A%20%20%20%20%7D%2C%0A%20%20%20%20ticketConnection%3A%20%7B%0A%20%20%20%20%20%20type%3A%20ticketConnection%2C%0A%20%20%20%20%20%20args%3A%20connectionArgs%2C%0A%20%20%20%20%20%20resolve%3A%20(_%2C%20args)%20%3D%3E%20connectionFromArray(exportObject.getTickets()%2C%20args)%0A%20%20%20%20%7D%0A%20%20%7D)%2C%0A%20%20interfaces%3A%20%5BnodeInterface%5D%0A%7D)%3B%0A%0Aconst%20queryType%20%3D%20new%20GraphQLObjectType(%7B%0A%20%20name%3A%20'Query'%2C%0A%20%20fields%3A%20()%20%3D%3E%20(%7B%0A%20%20%20%20node%3A%20nodeField%2C%0A%20%20%20%20viewer%3A%20%7B%0A%20%20%20%20%20%20type%3A%20viewerType%2C%0A%20%20%20%20%20%20resolve%3A%20()%20%3D%3E%20exportObject.getViewer()%0A%20%20%20%20%7D%0A%20%20%7D)%0A%7D)%3B%0A%0Aexport%20default%20new%20GraphQLSchema(%7B%0A%20%20query%3A%20queryType%0A%7D)%3B%0A

josephsavona commented 8 years ago

@mario-jerkovic This is super helpful, thank you for taking the time to create this. Having the playground instance makes it pretty clear what's happening - the setState from the parent causes RelayContainer to recheck its props and it ends up comparing the variables in those props (empty, nothing is being passed) with what it fetched (the local setVariables changes) and reporting the discrepancy. This is just a warning so feel free to ignore for now, I'll work on a fix (I'd normally suggest creating a PR but this is a notoriously tricky area in Relay).

mario-jerkovic commented 8 years ago

No problem, I am glad that I could help 😃

philiptzou commented 8 years ago

Thank goodness I found this page. I have the same scenario as @jardakotesovec and get the same warnings. It took me days to suspect that I used Relay wrongly.

mjurincic commented 7 years ago

Any news on this, in our relay app we have the global filter that starts with initialVariables but can be modified later by users interaction with users setVariables. There is no parent to pass this props down and we are receiving this warning.

josephsavona commented 7 years ago

@mjurincic We're working on a new variation of RelayContainer that avoids issues such as these, and that will hopefully be available within the next release or two.

For now, this is just a warning.

wincent commented 7 years ago

Closing this as there's nothing actionable here. New Relay APIs and core are already rolling out to master, and will continue to do so over the coming weeks/months. Thanks for all the input on this issue, folks!

LyndaOuni commented 6 years ago

hello, i have the same problem with react relay, i need help please, class ProductRoute extends Relay.Route { static routeName = 'BasketProductsRoute'; static queries = { product: queriesComponent => Relay.QL query { node(id: $id) { ${queriesComponent.getFragment('product')} } }, }; } const AddToBasketWarrantyContainer = Relay.createContainer(AddToBasketWarrantyPage, { fragments: { product: () => Relay.QLfragment on Product { id uuid logo ref ecoPart category { id } images { uris(size: [MEDIUM]) } brand ref name { text } discount ean promotionsList{ idPrmotion, seuilMinumumDeclenchement, numeroPromotion, typeSeuilDeclenchement, finOffre, valeurDeclencheur, cibleClient, cumulable, uniteRemise, remiseEnseigne, typeRemise, montantMaximumRemise, statut, financement, remiseFournisseur, debutOffre, typeDeclencheur, priceProd, priceProdDiscounted, discount, valuePromo } tvaList { SWListProd { idTva DUREEANNEE isSelected DUREE PVTTC TAUX DESIGNAT PRIXMAX SERVICETYPE GENCOD }, SPCWListProd { idTva, DESIGNAT, SERVICETYPE, COMMPREST, LBPREST, CDPREST, ADDITIONALINFO, isSelected }, SRTWListProd{ idTva, DESIGNAT, SERVICETYPE, isSelected, value } }, price { integralPart fractionalPart valueInCents } categoriesOfProduct { catLevel1, catLevel2, catLevel3 } basePrice { integralPart fractionalPart } codeRemu codeGLN categoriesOfProduct { catLevel1 catLevel2 catLevel3 } creditWithWarranty }, }, });

warning : relay Container: component `Connect(Service Warrantywas rendered with variables that differ from the variables used to fetch fragmentproduct. the fragment was fetched with varibales (not fetched), but rendered with variables {} .