Word of warning re: hierarchicalMenu

I had some strange behaviour while using a custom HierarchicalMenu:

If my second level values have the same identifier as some of my first level values some unexpected stuff occurs:

currentRefinement = 0
refine(0 < 1)
currentRefinement = 0 < 1
refine(1) // Attempt to change top level category
currentRefinement = 0 // Expected 1

Curiously this only occurs if using checkboxes and their onChange={() => refine(item.value)}.

I figured out it was because I was using item.label as the react key and thus when I did the refine(1) it was supposed to be unmounting the sublevel item and re-rendering the proper top level item with its new value, their new keys were the same, but the isRefined was updated, causing the checkbox to call onChange and refine with the (old: as in the previous react render’s) item’s value.

So the solution is clear: find a unique key. However its not that simple, as each item doesn’t have an idea of who its parent is. I have to refactor List.js where we call renderItem to pass in the parent and generate the unique path from there. This parent should probably be passed in anyways.

// List.js
renderItem = (item, resetQuery, parentItem) => {
    if (!item.label) return null;
    const items = item.items && (
      <div>
        {item.items
          .slice(0, this.getLimit())
          .map(child => this.renderItem(child, item, item))}
      </div>
    );

    return (
      <div key={item.key || item.label}>
        {this.props.renderItem(item, resetQuery, parentItem)}
        {items}
      </div>
    );
  };

Even stranger is that top level category items don’t have the value property if they are refined.

This key below only works because I have two levels of depth and my labels are unique in a level

// HierarchicalMenu.js
renderItem = (item, parentItem) => {
 return ( 
  <div key={parentItem.label + '<' + item.label}>
  </div>
 )
}

Alternatively I could omit the key prop, and deal with the console warnings. In conclusion, it seems the List component currently calls renderItem in such a way that it is not always possible to generate a viable react key if you have duplication of value across category levels.

If the default HierarchicalMenu used checkboxes this behaviour would occur in the react-instantsearch library itself. But it uses buttons. :sweat_smile:

EDIT: It seems its not only the key prop, but rather the htmlFor and id of checkboxes/their labels in which this non-unique problem arises and it was that which was causing the strange behaviour.

Hi @david1,

I looked a the code for the HierarchicalMenu and you are right, the value is undefined when the attribute is refined. The problem seems to come from there, because if you have the correct value normally you will be able to generate the unique key for the element.

Is it possible to provide a working example of your issue? Will be easier to debug and fix the problem with a real example.

Hope that helps! :wink:

The HierarchicalMenu connector in general seems utterly random and unpredictable in terms of the ‘label’ and ‘value’ properties of items. Like I said the reproduction steps are to use a schema in which the top level and second level categories overlap. I don’t have neither the playground environment nor the time to create a debugging example for you, and I think this is sufficient to reproduce the issue.
1
1 > 1
1 > 2
2 > 1
2 > 2

Additionally to this issue, I’m getting a rather strange issue where second level items sometimes have the > in the value and sometimes don’t. What on earth is happening here? The label and value properties of items are entirely unpredictable it seems, and need to be a consistent format, or this weird behaviour needs to be documented.

03