Credits to React.gg
Rule #0: When a component renders, it should do so without running into any side effects.
Rule #1: If a side effect is triggered by an event, put that side effect in an event handler.
Rule #2: If a side effect is synchronizing your component with some external system, put that side effect in useEffect.
Rule #3: If a side effect is synchronizing your component with some outside system and that side effect needs to run before the browser paints the screen, put that side effect inside useLayoutEffect.
Rule #4: If a side effect is subscribing to an external store, use the useSyncExternalStore hook.
Rule #5: Whenever you need to access a reactive but non-synchronizing value inside of useEffect, look into abstracting that logic into useEffectEvent.