componentEngineering
React Fundamentals
Components, the hooks rules, the render model, and the traps that cause most React bugs.
1 item
Links1
01NotesNote
The mental model
A component is a function of its props and state that returns UI. React re-renders when state or props change, diffs the result against the previous render, and applies the minimal DOM changes. "Re-render" means React calls your function again — it does not mean the DOM was touched. Most performance confusion comes from conflating the two.
Hooks — the rules that actually matter
- Only call hooks at the top level of a component or another hook — never in conditions, loops, or after an early return. React tracks hooks by call order.
useState— local state; setter triggers a re-render. Updates are batched, and state is a snapshot per render (countinside a closure is the value at render time, not "live").useEffect— for synchronizing with external systems (subscriptions, DOM, network), not for deriving data. If you can compute it during render, don't put it in an effect.- The dependency array must list every value from the render scope the effect uses. Lying to it causes stale closures. Let the
exhaustive-depslint rule guide you. useRef— a mutable box that survives renders without triggering one. For DOM nodes and "I need to remember something but not re-render."
Common traps
- Derived state in state. If a value can be computed from props/state, compute it during render — don't mirror it into
useStateand sync with an effect. - Missing
keyin lists, or using array index as key when the list reorders — causes subtle state-bleed bugs. Use a stable unique id. - New object/array/function each render passed as a prop defeats memoization. Stabilize with
useMemo/useCallbackonly when it matters. - Effects that should be event handlers. Reacting to a user action? That's an event handler, not an effect.
Composition over configuration
- Prefer passing
childrenand small focused components over giant prop-driven mega-components. - Lift state only as high as it needs to go — co-locate it with the closest common ancestor that needs it, no higher.