Rendering should be pure, but real apps must also do impure things: fetch data, set up subscriptions, manipulate the DOM directly, start timers. useEffect is the hook for these side effects — code that runs after React has rendered and committed to the screen, synchronising your component with external systems. It is one of the most powerful and most misused hooks.
An effect takes a function and a dependency array. React runs the function after render, and re-runs it whenever a value in the dependency array changes. The effect can return a cleanup function that React calls before the next run and on unmount — essential for tearing down subscriptions and timers so they do not leak.
The hardest part of useEffect is knowing when not to use it. Many things developers reach for effects to do — deriving state, responding to events, transforming data for rendering — should not be effects at all. This lesson covers how effects run, the dependency array, cleanup, and the crucial discipline of using effects only to synchronise with external systems.