javascriptreactjsgraphqlrelaymodernreact-relay

Relay-Modern FragmentContainer data not populated


I'm using Relay Modern to try to load data into a FragmentContainer. I'm using the familiar Container (Smart) / Presenter (Dumb) pattern and the data is not being passed into my child Container as expected. However, if I use Relay's @relay(mask: false) directive to see if the fragment's data is properly loaded by QueryRenderer, the fragment data is there.

I don't understand why the data is not being sent to my Container. Any help is much appreciated.

ScreenContainer.js (renders QueryRenderer):

/* ScreenContainer.js */

import ScreenPresenter from './ScreenPreseenter';
const query = graphql`
query ScreenContainerQuery($id: ID!) {
  viewer {
    User(id: $id) {
      id
      ...NestedFragmentContainer_user
    }
  }
}`
export default class ScreenContainer extends Component {
  render() {
    <QueryRenderer 
      query={query} 
      variables={{id: id}} 
      render={() => <ScreenPresenter />} 
    />
  }
}

ScreenPresenter.js:

/* ScreenPresenter.js */

import NestedFragmentContainer from './NestedFragment';

export default class ScreenPresenter extends Component {
  render() {
    return <NestedFragmentContainer />
  }
}

And finally, NestedFragmentContainer.js:

/* ./NestedFragmentContainer.js */

class NestedFragmentContainer extends Component {
  render() {
    const { user } = this.props;
    console.log(user); // <-- Always null, not undefined
    return <Text>{user.account.name}</Text>;
  }
}
export default createFragmentContainer(
  NestedFragmentContainer,
  graphql`
    fragment NestedFragmentContainer_user on User {
      account {
        name
      }
    }
  `

Furthermore, whenever NestedFragmentContainer renders, I see an error that its user prop is undefined. However, console.log() shows that its value is in fact null, and not undefined.

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

Does anyone have any idea why the FragmentContainer isn't being rendered with its data?


Solution

  • Assuming the query was successful, the data needs to get passed to the rendered component. As stated in Relay modern docs:

    QueryRenderer is the root of a Relay tree. It takes a query, fetches the data and calls the render callback with the data.

    In your case, the queryRenderer should look like this:

    render() {
        return (
          <QueryRenderer
            environment={environment}
            query={query}
            variables={{id: id}}
            render={({error, props}) => {
              if (error) {
                return <div>{error.message}</div>
              } else if (props) {
                /*  Here is the crucial part */
                return < ScreenPresenter data={props.viewer} />               
              }
              return <div>Loading</div>
            }}
          />
        )
      }
    }
    

    Then you will be able to pass the props down from the container component (smart) to the presentational one (dumb).