is the approach here counter-indicated by the React documentation?
Yes. Normally, updating the state should call its setState function, but we see here that using sort mutates sortedItems without calling setSortedItems. The approach to use setSortedItems instead can be implemented like so:
useEffect(() => setSortedItems([...sortedItems].sort()), [sortedItems])
(I know you said not looking for alternative approaches, but please take this as an example so I can explain.)
The important point is that this will not mutate the previous sortedItems before triggering a render. This is so that the next DOM render and anywhere that reads sortedItems will be consistent.
Update
Although the render and accesses to sortedItems will be consistent, it may not contain the value that's expected in subsequent updates because of how React's state updates are queued asynchronously (this issue is also prevalent in OP's example). The issue arises when the time to sort subsequent sortedItems vary greatly, but there can be other causes as well.
React docs explains this behavior in their docs for setState:
https://reactjs.org/docs/react-component.html#setstate
Subsequent calls will override values from previous calls in the same cycle, so the quantity will only be incremented once. If the next state depends on the current state, we recommend using the updater function form, instead:
this.setState((state) => {
return {quantity: state.quantity + 1};
});
In our example, it's a minor change of adding a callback to the example:
useEffect(() => setSortedItems((prevSortedItems) => [...prevSortedItems].sort()), [sortedItems])