Relay: Warning: createFragmentSpecResolver: Expected prop `data` to be supplied to `Relay(List)`, but got `undefined`. Pass an explicit `null` if this is intentional.

Created on 30 Apr 2018  路  9Comments  路  Source: facebook/relay

Repo

Following this tutorial.

I've tried with repo as is and with data={props.data} as a prop.

What's going on?

Most helpful comment

Also, to the maintainers of Relay, I would advise making this issue I ran into--passing down the right prop at the <QueryRenderer/> level (which is different from what you'll pass down at all levels after)--a bit more explicit in the documentation (i.e. "Thinking in Relay", "<QueryRenderer/>"--which does not provide a multi-level example, and "FragmentContainer" under "createFragmentContainer").

Just add a block quote that highlights the distinction made in this issue: https://github.com/facebook/relay/issues/1732

Because of the way the documentation comes off, I thought I just had to collocate the fragment with my component--not ALSO pass a prop down at every level of my component hierarchy if I use <QueryRenderer/>.

And I thought this because of content like:

With typical approaches to data-fetching we found that it was common for two components to have implicit dependencies. For example <StoryHeader /> might use some data without directly ensuring that the data was fetched. This data would often be fetched by some other part of the system, such as <Story />. Then when we changed <Story /> and removed that data-fetching logic, <StoryHeader /> would suddenly and inexplicably break.

Passing down a prop at every level of your component hierarchy is still a dependency.

All 9 comments

Just got data to render.

Component Hierarchy BEFORE:

app: QueryRenderer >> index >> Router >> List: fragmentContainer >> Link: fragmentContainer

By removing the fragments and placing their content in app.js's query, I am able to pass their data down. However, when I used

// app.js

const query = graphql `query appQuery { ...List }`


// List.js

export default createFragmentContainer(List, graphql`
  fragment List on RootQueryType {
    allLinks {
      ...Link
    }
  }
`);


// Link.js

export default createFragmentContainer(Link, graphql`
  fragment Link on Link {
    id
    description
    url
  }
`);

this returned an empty List object in the QueryRenderer, even though the query + fragments works perfectly on GraphiQL.

Interestingly, _app: QueryRenderer >> index >> Router >> List >> Link: fragmentContainer_ works with the adjustment of using link["__id"] instead of link.id in List.js when iterating over allLinks.

I.e.

// app.js

const query = graphql `query appQuery { allLinks { ...Link } }`

Oddly, I added back ...List and now the app is rendering.

This means that my issue was that I was passing the wrong props down the component hierarchy. The correct prop to pass down at each level is:

  • app: data={props}
  • index: data={this.props.data}
  • Router: render={() => <List data={props.data}/>
  • List: props.data.allLinks.map(link => <Link key={link["__id"]} data={link}/>
  • Link: const {description, url} = this.props.data;

So I was passing data={props.data} in app.js, which at the top-level is undefined, instead of data={props}

As advice to anyone who runs into a similar issue:

  1. console.log the props at each level of your component hierarchy to see if they suddenly disappear at one level; if so, adjust the prop you are passing at the level above

  2. if you can't figure out what's going on (like me), do as above--remove the complexity that comes with using fragments by just putting the query at the top-level; then repeat (1) until your data renders; finally, introduce one fragment and get the data to render--keep doing this until you have the level of abstraction/collocation you want

This is a problem in your QueryRenderer logic

Also, to the maintainers of Relay, I would advise making this issue I ran into--passing down the right prop at the <QueryRenderer/> level (which is different from what you'll pass down at all levels after)--a bit more explicit in the documentation (i.e. "Thinking in Relay", "<QueryRenderer/>"--which does not provide a multi-level example, and "FragmentContainer" under "createFragmentContainer").

Just add a block quote that highlights the distinction made in this issue: https://github.com/facebook/relay/issues/1732

Because of the way the documentation comes off, I thought I just had to collocate the fragment with my component--not ALSO pass a prop down at every level of my component hierarchy if I use <QueryRenderer/>.

And I thought this because of content like:

With typical approaches to data-fetching we found that it was common for two components to have implicit dependencies. For example <StoryHeader /> might use some data without directly ensuring that the data was fetched. This data would often be fetched by some other part of the system, such as <Story />. Then when we changed <Story /> and removed that data-fetching logic, <StoryHeader /> would suddenly and inexplicably break.

Passing down a prop at every level of your component hierarchy is still a dependency.

@English3000 thanks for pointing this out! Happy to take PRs updating the docs

@jstejada As requested: https://github.com/facebook/relay/pull/2435

If this looks like a good start, I can also add some more explicit language to the 3 aforementioned pages (regarding the need to pass down props properly 馃槈)...

@jstejada Just wanted to touch in on how my content's been received.

Was this page helpful?
0 / 5 - 0 ratings