Recently I've made a component for recursive classifier with Relay
.
I made it with two ways. One of which did not work and the second worked.
From the end-user side they both look the same with the same functionality.
In short the task is pretty much a general recursive data fetching with fetching
on next level expand.
The first way:
Fetch data after setting the relay variable expand
. It is made via the
recursive fragment composition. The main part is this:
const CategoryItemContainer = Relay.createContainer(CategoryItem, {
initialVariables: {
expanded: false,
},
fragments: {
category: (variables) => Relay.QL`
fragment on Category {
id
name
hasChildren
${CategoryItemSubcategoryListContainer.getFragment('categories').if(variables.expanded)}
}
`,
},
});
const CategoryItemSubcategoryListContainer = Relay.createContainer(CategoryItemSubCategoryList, {
fragments: {
categories: () => Relay.QL`
fragment on Category {
categories(first: 10000) {
edges {
node {
${CategoryItemContainer.getFragment('category')}
}
}
}
}
`,
},
});
This way it is supposed that the Relay.RootContainer
is called just once. It
did not work for me but I know that others implemented it and everything's OK (it's
a subject for another post).
The second way:
The second way worked for me easy. I don't use Relay
variables but I call
Relay.Renderer
for the next level of recursion depending on the UI component's
state. Like this:
{this.state.hasOwnProperty(category.id) ? // <- changing the state triggers the recursion
<Relay.Renderer
Container={CategoryItemSubCategoryListContainer}
queryConfig={new CategoryRoute({ id: category.id })}
environment={Relay.Store}
render={({ done, error, props, retry, stale }) => {
if (error) {
return 'Error';
} else if (props) {
return <CategoryItemSubCategoryListContainer {...props}
maxLevel={maxLevel}
currentLevel={currentLevel + 1}
activeCats={this.props.activeCats}
elementSelectedCallback={elementSelectedCallback}/>;
}
return (
<ul className="dropdown-menu" aria-labelledby="dLabel">
<li>
<div className="list-group-item"><p className="text-center"><img src="img/ajax-loader.gif"/></p></div>
</li>
</ul>
);
}}
/> : ''}
This works just as I expected to. Moreover I have a nice loader icon for the next level everytime.
So, having this I've got three questions:
The first
Is any of these methods the preferrable one? Maybe there are drawbacks
somewhere that I don't know? I'd like to understand this since I'm introducing
Relay
to my company and I'm willing to replace all the legacy frontend with
React
and Relay
.
The second
At some point in time a user will pick a category from this recursive classifier and I will have to get the full path of data that led to the current level. I mean if a user picks a category at the level 3 of the hierarchy, I must give back these data:
[root cat id, root cat name],
[level 1 cat id, level 1 cat name],
[level 2 cat id, level 2 cat name]
So when I catch the event of picking inside the component at the level 2 how can
I get the full path from the root category from Relay
? I thought that I can
use some Relay
API to get them from store? Or do I have to implement this
store myself?
The third
As I said in the second way of implementation there's a nice feature that I
get the loading spinner every time the Relay.Renderer
is called. How can this
be done in the first way? I mean in the first way data fetching is hidden inside
fragment composition and and is triggered by the setVariables
. Should I
trigger the spinner right before the setVariables
method and then turn it off
in the onReadyStateChange
of the only Relay.RootContainer
? But then it seems
like I have to make a global store of spinners' state for rendered containers..
I'm confused here..