Skip to content

<Menu>/useMenu no longer functioning correctly with the new Disjunctive facet search (v0.11.0) #1007

Open
@Vashiru

Description

@Vashiru

Description
It appears that the

element is no longer functioning correctly with the new Disjunctive facet search. This appears to be because the isRefined property is no longer properly being set. I suspect this is because it's doign multiple calls to the server to recalculate all the facets, through which the isRefined property ends up as false.

To be more specific about my scenario: I'm using useMenu of the react-instantsearch-hooks-web module to create a custom menu. I do this because I want all options to be visible at all times (not depending on what's in the results), have a 'Show all' option and to avoid the behaviour that when I click an item again, it deselects the filter.

I use the isRefined variable to see if I need to check the radio button for that particular filter.

Expected behavior
The isRefined property is properly set when you've refined that facet in your current search.

Current behavior
When picking facets using useMenu the iseRefined value remains false, unless I also pick facets in different filters. The currently refined facet also appears to disappear completely from items when there are no longer hits in the results based on the other facets in the search. This wasn't previously the case. In 0.30.0 it remained present and set as 'isRefined' because it was part of all refinements.

I've tried setting keepZeroFacets=true, this doesn't help either, it just makes items turn into an empty array all the time. It also appears the counters for useRefinementList.

Sample code:
Sample code to create a useMenu with radio buttons containing the following items:

  • All items
  • Items where ContentSubject is set to MUSIC
  • Items where ContentSubject is set to DRAMA
  • Items where ContentSubject is set to DANCE

The shouldRefine function serves 2 purposes:

  • It checks if the value you're picking to refine, is the one currently already selected, if so it does nothing to avoid deselecting the filter (which is the default behaviour of useMenu. It makes sense if you're not using radio buttons, but we want radio buttons, so that becomes an issue).
  • It avoid filtering twice in a row on "", as that triggers an error. Calling refine("") the first time resets the facet, calling it again causes an error.
function ContentSubjectFilter() {
  const { items, refine } = useMenu({
    attribute: "contentSubject",
  });

  const contentSubjects = ["MUSIC", "DANCE", "DRAMA"]; // normally they come from a databse, but I've hard coded them here for the sample

  function shouldRefine(items, valueToRefineTo) {
    console.log(items); // Here you can see that "isRefined" is no longer being set properly starting with the 2nd option you pick. 
    let isCurrentlyRefined = !!items.find((item) => item.isRefined == true);

    if (isCurrentlyRefined && valueToRefineTo === "") {
      return true;
    } else if (!isCurrentlyRefined && valueToRefineTo === "") {
      return false;
    }

    let isNewRefineValueSameAsCurrentRefinement = !!items.find((item) => {
      return item.isRefined === true && item.value === valueToRefineTo;
    });
    if (isNewRefineValueSameAsCurrentRefinement) return false;

    return true;
  }

  return (
    <ul>
      <li>
        <label
          onClick={(event) => {
            event.preventDefault();
            if (shouldRefine(items, "")) refine("");
          }}
        >
          <input
            checked={!!items.filter((item) => item.isRefined === true)}
            name={"contentSubjectRefinement"}
            type="radio"
            value={""}
            defaultChecked
          />
          Alles
        </label>
      </li>
      {contentSubjects.map((contentSubject) => {
        return (
          <li key={contentSubject}>
            <label
              onClick={(event) => {
                event.preventDefault();
                if (shouldRefine(items, contentSubject)) refine(contentSubject);
              }}
            >
              <input
                checked={
                  !!items.find(
                    (item) => item.value === contentSubject && item.isRefined
                  )
                }
                name={"contentSubjectRefinement"}
                type="radio"
                value={contentSubject}
              />
              {contentSubject}
            </label>
          </li>
        );
      })}
    </ul>
  );
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions