Relay: Support interpolation of route-conditional fragments that return an array of fragment references

Created on 3 Mar 2016  Â·  11Comments  Â·  Source: facebook/relay

Presently there is a limitation in Relay that requires that any interpolation you perform in a Relay.QL block must evaluate to:

  • a fragment reference

${Foo.getFragment('viewer')}

  • an array of fragment references

${COMPONENTS.map(c => c.getFragment('viewer'))}

  • a route-conditional function that returns _exactly one_ fragment reference

${route => COMPONENTS[route].getFragment('viewer')}

The task at hand is to enable the interpolation of route-conditional functions that return an array of fragment references.

${route => COMPONENTS.map(c => 
  c.getFragment('treasure').if(variables[`${route}Unlocked`])
)}
good first bug help wanted

Most helpful comment

Oops, massive brain fart on my part. 😑

Would it make sense for the signature for conditional fragments to in fact be:

(RelayMetaRoute, Variables) => ?RelayQueryNode | Array<?RelayQueryNode>

It'd be a minor quality-of-life improvement in the case above, since it'd allow avoiding the apparently unnecessary extra function bind above.

All 11 comments

This is the same issue too: #775

I have a similar use case. Can someone please elaborate on that 'route-conditional function'? Where is that 'route' parameter coming from? Thanks

If you interpolate a function into your query:

viewer: () => RelayQL`
  fragment on Viewer {
    ${route => ...}
  }

That function will receive the routeName of the Relay.Route you used with Relay.RootContainer as its first argument, and will expect that you return a single fragment reference (eg. that which is returned from Container.getFragment('viewer')).

@steveluscher Thanks. I guess it won't work for me. I'm using react-router so the given route seems like something that was generated by it. I actually need to choose the component based on a parameter (called 'hash' in my case), but I don't see any way to do it...

Closed by #915.

Apologies if I'm missing something here, but with the

${route => COMPONENTS.map(c => 
  c.getFragment('treasure').if(variables[`${route}Unlocked`])
)}

syntax – is it the case that you _must_ define this function inline to the fragment if you want to have access to variables? In other words, I couldn't have a separate:

const conditionalFragment = route => (
  COMPONENTS[route.name].getFragment('treasure', variables)
);

@taion You can define the function wherever you want, as long as you make sure that variables are in scope.

The problem is that variables are only in scope if I am defining this within the fragment. If I want a reusable conditional fragment as above, where I define it outside the fragment definition in Relay.createContainer, there's no way for variables to be in scope.

@taion This is just like any function - if you need access to variables in the helper, you have to pass it:

const conditionalFragment = (route, variables) => (
  COMPONENTS[route.name].getFragment('treasure', variables)
);
createContainer(Foo, {
  fragments: {
    foo: variables => Relay.QL`fragment on Foo {
      ${route => conditionalFragment(route, variables)}
    `,
  },
});

Oops, massive brain fart on my part. 😑

Would it make sense for the signature for conditional fragments to in fact be:

(RelayMetaRoute, Variables) => ?RelayQueryNode | Array<?RelayQueryNode>

It'd be a minor quality-of-life improvement in the case above, since it'd allow avoiding the apparently unnecessary extra function bind above.

Was this page helpful?
0 / 5 - 0 ratings