One common mistake I've seen often with beginners is using parallel state and useEffect where a memo and callback would be better.
Suppose I have a state that's an object reflective of my API/domain, but I need to convert it into a different kind of complex object for a UI framework component that uses more generic, less domain-specific properties. (say, a dynamic form)
A common thing is to have a separate state for setter/getter and a useEffect that looks at the new form state and updates the old domain state, another looking for changes in the incoming props and recreating the new state. Aside from the risks of getting into a useEffect looping situation, it can lead to other errors if there's any way they get out of sync (often, due to trying to avoid the looping).
Instead of parallel state, have a useMemo take the domain state and turn it into the property value, and a callback that takes the updated property value from the contained component and setState it back. one version of the truth, so to speak.