algolia / instantsearch

⚑️ Libraries for building performant and instant search and recommend experiences with Algolia. Compatible with JavaScript, TypeScript, React and Vue.

Home Page:https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/js/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`useRefinementList` in Show Less state doesn't respect `transformItems` sort

avremel opened this issue Β· comments

πŸ› Current behavior

According to the docs, transformItems can be used to reorder the refinement values with a custom sort.

When a custom sort is used together with Show More/Show Less functionality, the custom sort isn't applied in the Show Less state. It's only applied in the Show More state.

πŸ” Steps to reproduce

  1. The static sort is defined as Whirlpool, Sony, Metra (then the rest).
  2. Observe that in the default state of Show Less, the first three items are incorrectly Metra, Insignia, Samsung.
  3. Observe that when selecting Show More, the first three items are correctly Whirlpool, Sony, Metra.
Screen Shot 2023-05-29 at 10 15 55 AM Screen Shot 2023-05-29 at 10 16 05 AM

Live reproduction

https://codesandbox.io/p/sandbox/next13-4-4-forked-79jevr?file=%2Fcomponents%2FBrands.js%3A11%2C78

πŸ’­ Expected behavior

A custom sort in transformItems is respected in the Show Less state.

Package version

algoliasearch 4.17.1, react-instantsearch-hooks-web 6.44.0

Operating system

Mac 11.6.5

Browser

Chrome 113.0.5672.126

Code of Conduct

  • I agree to follow this project's Code of Conduct

While this is still something I'd like to look into fixing, you can also use "Facet Ordering" (docs: https://www.algolia.com/doc/guides/building-search-ui/ui-and-ux-patterns/facet-display/js/) to pin certain facets, and not need to use transformItems to sort the items.

We have quite a complex sort - for example: sort brands by most popular per category. It would be difficult to manage with facet ordering.

I believe this is happening because limit gets evaluated before transformItems, which is logical for some use cases, but doesn't seem to match yours, as that causes the items aren't guaranteed to be in place.

However, there's also the sortBy option which does get evaluated before transformItems and seems to match your use case quite well:

https://codesandbox.io/p/sandbox/refinement-list-sort-issue-forked-pjx46b?file=%2Fcomponents%2FBrands.js%3A35%2C14

useRefinementList({
      attribute: "brand",
      showMore: true,
      limit: 5,
      sortBy: useCallback((a, b) => {
        if (
          CUSTOM_BRAND_SORT[a.escapedValue] !== undefined &&
          CUSTOM_BRAND_SORT[b.escapedValue] !== undefined
        ) {
          return (
            CUSTOM_BRAND_SORT[a.escapedValue] -
            CUSTOM_BRAND_SORT[b.escapedValue]
          );
        }
        if (CUSTOM_BRAND_SORT[a.escapedValue] !== undefined) {
          return -1;
        }

        if (CUSTOM_BRAND_SORT[b.escapedValue] !== undefined) {
          return 1;
        }

        return 0;
      }, []),
    });

@Haroenv Thanks, didn't realize that sortBy accepts a function too.

Sandbox links is broken for me.

Sorry, I'm not used to the new sandbox system that automatically makes links private (instead of public).

As sortBy runs first, I think this solves your use case, and the documentation doesn't need to be updated, as the function is already mentioned (not sure how to make it clearer)