3

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..

Grigory
  • 992
  • 2
  • 18
  • 34

0 Answers0