6

My use case is that I have a Node application that consumes data from a CMS, and in that CMS I give the users the ability to select a React Component as a "Layout". I'd like for Relay to be able to get a GraphQL Fragment from that dynamically select component. When the Layout's parent component mounts, it goes through its query and gets the layout component it needs and sets a Relay variable - it then needs to get a fragment from that component. Is there a way to do that?

Here is the parent level query:

export default Relay.createContainer(WordpressPage, {
initialVariables:{
 Component: null,
 page: null,
 showPosts: false,
 limit: 5
},
prepareVariables(prevVars){
 return{
 ...prevVars,
 showPosts: true
 }
},
fragments: {
 viewer: ({Component, showPosts, limit}) => Relay.QL`
 fragment on User {
 ${PostList.getFragment("viewer", {limit:limit}).if(showPosts)},
 page(post_name:$page){
 id,
 post_title,
 post_type,
 post_content,
 thumbnail,
 layout{
 meta_value
 }
 }
 }
 `,
 },
});

As you can see, it queries and gets a layout field. When it mounts, it sets the Relay Component variable to be a React Component. Instead of "PostList.getFragment", I'd really like to be able to do a Component.getFragment.

Dmitry Shvedov
3,3244 gold badges41 silver badges57 bronze badges
asked Jan 28, 2016 at 17:09

1 Answer 1

8

What you must do here is to interpolate all possible fragment references into the query. Starting with Relay v0.7.1 you will be able to interpolate into your query an array of fragment references:

const COMPONENTS = [
 [PostList, 'showPosts'],
 [OtherKindOfList, 'showOthers'],
 /* ... */
];
static initialVariables = {
 showPosts: false,
 showOthers: false,
 /* ... */
};
fragments: {
 viewer: variables => Relay.QL`
 fragment on User {
 ${COMPONENTS.map(([Component, variableName]) => {
 const condition = variables[variableName];
 return Component
 .getFragment('viewer', {limit: variables.limit})
 .if(condition);
 })},
 # ...
 `,
 },
});

Warning: Presently there is a limitation in Relay that requires that the interpolated expression return either:

  • 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 original poster's use case was for a route-conditional function that returns an array of fragment references, which is not yet supported. See the comments for more information. See also facebook/relay/issues/896

answered Feb 18, 2016 at 1:16
Sign up to request clarification or add additional context in comments.

17 Comments

Thanks! Any idea when 0.7.1 will be released?
I released v0.7.1 a moment ago, just for you. :)
Will the condition only work for boolean variables? I couldn't set a 'Layout' variable and check that it equals a string?
I don't think so, because condition here represents a ‘variable’ data type, and not actually a raw boolean. This lets Relay evaluate the variable over time to see if the if() condition passes or fails.
Here is page Here is PostList
|

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.