Your example should work, and this is what happens in order, say when you pass new data or you use setSortOrder.

1 - You arrive inside the code of your hook

2 - You hook uses setSortedData to update it's sortedData state

3 - It returns a stale sortedData to your component (because it was read from useState before being modified)

4 - The call to setSortedData kicks in, changes the data in the state, triggers a new render of your component, which will use your hook again, and the hook will provide the right version of sortedData.

In a nutshell, you have one extra render. If you want to prevent that, you could use useMemo, like so:

function useSorting(initialSort, data) {
  const [sortOrder, setSortOrder] = useState(initialSort);
  const sortedData = useMemo(() => sortBy(sortOrder, data), [data, sortOrder]);

  return [sortedData, sortOrder, setSortOrder];

Your component will get the sorted data right away without having to go through an extra rendering loop, and you still have the benefits of having your sorting function called only if relevant information change (data, sortOrder).

Related Query

More Query from same tag