5

I'm looking for the good syntax to pass a variable from a parent container to a child container.

Let's say I have theses routes, with a global widget list on / and specific widget lists on /widgets/:WidgetListID.

Note: I use react-router-relay

<Route
    path='/' component={Layout}
  >
    <IndexRoute
      component={WidgetListContainer}
      queries={ViewerQueries}
    />
    <Route
      path='/widgets/:WidgetListID'
      component={WidgetListContainer}
      queries={ViewerQueries}
    />
  </Route>

It's the same <WidgetList/> component, rendered inside <WidgetListContainer/> inside <Layout/> and here is how I try to pass the WidgetListID variable:

Layout.js

class Layout extends React.Component {
  render() {
    return (
      <div>
       ...
        {children}
       ...
      </div>
    );
  }
}

WidgetListContainer.js

class WidgetListContainer extends React.Component {
  render () {
    return (
      <div>
       ...
        <WidgetList 
          viewer={viewer}
        />
      </div>
    )
  }
}

export default Relay.createContainer(WidgetListContainer, {
  initialVariables: {
    WidgetListID: null
  },
  fragments: {
    viewer: ($WidgetListID) => Relay.QL`
      fragment on User {
        ${WidgetList.getFragment('viewer', $WidgetListID)}
      }
    `,
  },
})

WidgetList.js

class WidgetList extends React.Component {
  render () {
    return (
      <div>
        <ul>
          {viewer.widgets.edges.map(edge =>
            <li key={edge.node.id}>{edge.node.widget.name}</li>
          )}
        </ul>
      </div>
    )
  }
}
export default Relay.createContainer(WidgetList, {
  initialVariables: {
    WidgetListID: null
  },
  fragments: {
    viewer: () => Relay.QL`
      fragment on User {
         widgets(first: 10, WidgetListID:$WidgetListID) { 
          edges { 
            node { 
              id, 
              name
            } 
          } 
        } 
      }
    `,
  },
})

I have no problem setting the WidgetListID variable directly inside the WidgetList relay container, it works perfectly fine, but as soon as I try to pass it from the WidgetListContainer relay container I have an empty data object {__dataID__: "VXNlcjo="}. Though, the variable is well printed in my getWidget() function. So something doesn't work at some point but I can't figure out what?

What would be the good syntax to pass the WidgetListID variable from the parent container to the child container?

Chris
  • 57,622
  • 19
  • 111
  • 137
Victorien
  • 181
  • 1
  • 7

2 Answers2

1

In the WidgetListContainer, change this:

fragments: {
    viewer: ($WidgetListID) => Relay.QL`
      fragment on User {
        ${WidgetList.getFragment('viewer', $WidgetListID)}
      }
    `,
  },

to

fragments: {
    viewer: ({WidgetListID}) => Relay.QL`
      fragment on User {
        ${WidgetList.getFragment('viewer', {WidgetListID})}
      }
    `,
  },

The first argument to the fragment builder is the Relay variables. So first you need to pull the WidgetListID variable out of the WidgetListContainer's variables, and then you can pass it into WidgetList.getFragment().

Note that the $ symbol is only used inside the Relay.QL template string. Inside the variables object, you refer to the variable by name, without the $.

steveluscher
  • 4,144
  • 24
  • 42
sefnap
  • 396
  • 4
  • 6
  • Thank you for your answer! I think I'm missing something again, I now have an error: `RelayFragmentReference: Variable 'WidgetListID' is undefined in fragment 'WidgetList'.`? – Victorien Sep 25 '15 at 08:55
  • Sorry; I made a mistake in the getFragment call; you need to pass in the `route` as well. So, it should be `WidgetList.getFragment('viewer', route, {WidgetListID})`. I updated the answer, so hopefully it'll work this time :) – sefnap Sep 25 '15 at 14:16
  • Hmm... I'm sorry, but it looks like my answer is incorrect. It's not working as I expected after all. :( – sefnap Sep 25 '15 at 15:09
  • No, it doesn't work :( Thank you for your help anyway! I'll keep trying... I'll let you know. – Victorien Sep 25 '15 at 18:29
  • Just to follow up, the best I could come up with was to pass the value into the child component's props, and have the child set the variable with the value. – sefnap Sep 27 '15 at 01:14
  • Yeah, I did that too, but I realized that the component was rendered two times: a first time with the variable as null and a second time with the passed variable. Finally, I just request the data in the WidgetListContainer et pass it as props to the widgetList. I told myself that if I could not pass a variable so I was going to pass the entire data. Why not? – Victorien Sep 28 '15 at 06:48
  • This answer was very close. I've edited it. Can you try again, and accept it if it works @Victorien? – steveluscher Dec 05 '15 at 00:39
0

Hi I also struggled with this for a bit. Change this:

 class WidgetListContainer extends React.Component {
  render () {
    return (
      <div>
       ...
        <WidgetList 
          viewer={viewer}
        />
      </div>
    )
  }
 }

to this:

class WidgetListContainer extends React.Component {
  render () {
    return (
      <div>
       ...
       <WidgetList
          WidgetListID={this.props.relay.variables.WidgetListID}
          viewer={viewer}
        />
      </div>
    )
  }
}

also in your WidgetList component's relay container don't forget to set initial variables to initialVariables: { WidgetListID: null }, this setup will make your WidgetListID variable available for your WidgetList component's relay container.

  • oh, and don't forget the change in previous answer – Ilyas Talgatuly Malgazhdarov Sep 27 '15 at 11:34
  • Thanks for your answer, I tried that too, but it's the same problem for me, empty data object `{__dataID__: "VXNlcjo="}`. Maybe I have a problem elsewhere? I don't understand because if I initialize the variable with any string it works. I only have this problem trying to pass the variable so I told myself that the problem was there but maybe not? – Victorien Sep 28 '15 at 07:01