| Syntax | When it runs | Use for |
|---|---|---|
| useEffect(fn) | after EVERY render | rarely — usually causes infinite loops |
| useEffect(fn, []) | once after mount only | fetch initial data, set up listeners, init libs |
| useEffect(fn, [a, b]) | after mount + when a or b changes | re-fetch when userId changes, sync state |
| useEffect(fn → cleanup, []) | cleanup runs on unmount | remove event listeners, cancel timers, close connections |
useLayoutEffect instead.