Rendering & Reconciliation
- Rendering = calling component functions to produce JSX (Virtual DOM).
- Reconciliation = diffing old vs new Virtual DOM to find minimal changes.
- React uses O(n) heuristic diffing (same type → update, different → replace).
- Re-render ≠ DOM update. DOM updates happen only if diff detects changes.
function App() {
const [count, setCount] = React.useState(0);
return <h1>{count}</h1>;
}
// setCount triggers re-render → diff → minimal DOM updateVirtual DOM
- Virtual DOM is a lightweight JS representation of real DOM.
- React compares previous and next Virtual DOM trees.
- Avoids expensive direct DOM manipulation.
- Core idea: compute changes in JS, then apply minimal DOM updates.
const vdom = {
type: "h1",
props: { children: "Hello" }
};Fiber Architecture
- Fiber is React’s reconciliation engine (React 16+).
- Breaks rendering into small units of work.
- Enables pause, resume, and prioritization.
- Foundation for concurrent rendering and smooth UI.
// Conceptual:
// work → pause → resume → commitRender vs Commit Phase
- Render phase: builds new tree, runs diffing (can be interrupted).
- Commit phase: applies changes to DOM (always synchronous).
- Effects (useEffect) run after commit.
- Never cause side effects during render phase.
useEffect(() => {
console.log("runs after commit");
}, []);State & Re-renders
- State updates trigger re-renders.
- React batches multiple state updates into one render.
- State is async and may be stale if not handled properly.
- Use functional updates when relying on previous state.
setCount(c => c + 1); // safe
setCount(count + 1); // may be staleuseEffect
- Runs after render commit (side effects only).
- Dependency array controls execution.
- Cleanup function runs before next effect or unmount.
- Common bugs: missing deps, infinite loops.
useEffect(() => {
const id = setInterval(() => {}, 1000);
return () => clearInterval(id);
}, []);useMemo vs useCallback
- useMemo memoizes values (expensive computations).
- useCallback memoizes functions (stable references).
- Helps prevent unnecessary re-renders.
- Overuse can harm readability without real benefit.
const value = useMemo(() => compute(a), [a]);
const fn = useCallback(() => doSomething(a), [a]);React.memo
- Prevents re-render if props are shallowly equal.
- Useful for pure functional components.
- Works well with useCallback/useMemo.
- Not useful if props always change.
const Child = React.memo(({ value }) => {
return <div>{value}</div>;
});Keys in Lists
- Keys uniquely identify list items during reconciliation.
- Stable keys prevent unnecessary re-renders.
- Never use index as key for dynamic lists.
- Bad keys can cause UI bugs and state mismatch.
{items.map(item => (
<Row key={item.id} />
))}Controlled vs Uncontrolled
- Controlled: form state managed by React.
- Uncontrolled: form state managed by DOM (refs).
- Controlled gives better validation and control.
- Uncontrolled useful for simple or performance-heavy forms.
// Controlled
<input value={val} onChange={e => setVal(e.target.value)} />
// Uncontrolled
<input ref={ref} />Context API
- Used to share state globally without prop drilling.
- Triggers re-render for all consumers on change.
- Can cause performance issues if overused.
- Optimize using multiple contexts or selectors.
const ThemeContext = React.createContext();
const value = useContext(ThemeContext);Concurrent Rendering (React 18)
- Allows interruptible and prioritized rendering.
- Improves UI responsiveness.
- startTransition marks low-priority updates.
- Does not mean multi-threading — still single-threaded JS.
startTransition(() => {
setSearchQuery(input);
});