Search code examples
reactjsreact-hooksalgolia

How to avoid calling `useCallback` conditionally when value isn't always a function


useRefinmentList is an Algolia hook which accepts a sortBy prop.

The definition of sortBy is type: string[] | (a: FacetValue, b: FacetValue) => number.

If I pass in a sort function I wrap it in a useCallback, otherwise I pass in an array. This violates the rule that hooks can’t be called conditionally. In this case, useCallback is only called if sortBy is a sort function.

My code right now:

useRefinementList({
  attribute: 'my_attribute',
  sortBy: sortBy?.length
    ? sortBy
    : useCallback(
        (a, b) => myCustomSortFunction(a, b, attribute),
        [attribute]
      ),
})

How can I refactor my code to conform to the rule?


Solution

  • You can use useMemo instead of useCallback:

    useRefinementList(useMemo(
      () => ({
        attribute: 'my_attribute',
        sortBy: sortBy?.length
          ? sortBy
          : (a, b) => myCustomSortFunction(a, b, attribute),
      }),
      [sortBy, attribute]
    ))
    

    or

    useRefinementList({
      attribute: 'my_attribute',
      sortBy: useMemo(
        () => sortBy?.length
          ? sortBy
          : (a, b) => myCustomSortFunction(a, b, attribute),
        [sortBy, attribute]
      ),
    })