80 React Interview Questions and Answers (2026)

React is still the default way teams build user interfaces, and it keeps moving, hooks, concurrent rendering, and now Server Components and React 19. Interviewers expect real fluency, not buzzwords. Walk in shaky on hooks, rendering, or state and you will lose the offer to someone who is not.
This is 80 questions with tight, interview-ready answers and code where it actually helps. They're worked Junior to Mid to Senior, so you build from fundamentals to reconciliation, concurrent rendering, and server components. Work through them and you'll know your stuff cold.
Q1.What does it mean to lift state up, and what architectural problem does this solve?
Lifting state up means moving shared state to the closest common ancestor of the components that need it, then passing it down via props. It solves the problem of keeping sibling components in sync around a single source of truth.
The problem it solves: Two siblings can't read each other's state directly; duplicating it leads to drift and bugs.
The pattern:
The parent owns the state and passes the value down plus a callback to update it (value={x} onChange={setX}).
Children become controlled by the parent, so all consumers always see consistent data.
Trade-off: Lifting too high causes prop drilling; when many distant components need it, prefer Context or a state library.
Q2.What is prop drilling and what are the built-in React ways to solve it?
Prop drilling is passing data through many intermediate components that don't use it, just to reach a deeply nested consumer. It makes refactoring brittle and clutters components with props they only forward.
Why it's a problem: Intermediate components are coupled to data they don't care about; renaming or moving props ripples through the tree.
Built-in solutions:
Context: createContext + a provider, consumed with useContext, to share values (theme, auth, locale) without threading props.
Composition / children: pass JSX as props so the owner that has the data renders the consumer directly, avoiding deep passthrough.
Caveat with Context:
Every consumer re-renders when the context value changes; split contexts or memoize the value for performance.
It's not a full state manager; for large global state consider Redux, Zustand, etc.
Q3.What is prop drilling, and at what point does it become a problem?
Prop drilling is passing data through many intermediate components that don't use it themselves, just to reach a deeply nested child. It becomes a problem when those intermediaries become coupled to props they only forward.
What it looks like: A value in a top component is threaded through 3-4 layers of components as props until a leaf finally consumes it.
Why it hurts:
Intermediate components must accept and forward props irrelevant to them, adding noise.
Refactors are brittle: renaming or adding a prop touches every layer in the chain.
When it's fine vs. a problem:
One or two levels is normal and explicit, often preferable to abstraction.
It's a problem when the chain is deep, widely shared, or changes often.
Fixes:
Use Context for truly global/shared data (theme, auth, locale).
Use component composition (pass JSX via children) so data stays where it's used.
Reach for a state library only when sharing is large-scale.
Q4.How does React handle one-way data flow, and why is this considered an advantage over two-way data binding?
React enforces one-way (top-down) data flow: data passes from parent to child via props, and children communicate back only by calling callbacks the parent supplies. This makes a single owner the source of truth, which is more predictable than two-way binding where any side can mutate shared data.
How it works:
Parent holds state and passes it down as read-only props.
Child requests changes by invoking a callback prop; the parent updates its own state, then re-renders down.
Why it's an advantage:
Predictability: data changes in one place, so you can trace where any value came from.
Easier debugging: bugs trace upward to the owner rather than spreading across mutual bindings.
Explicit contracts: components are pure functions of their props, easy to test and reason about.
Two-way binding contrast:
Frameworks that auto-sync view and model can change state from multiple directions, making the source of truth ambiguous.
React simulates two-way binding for forms explicitly: value down via props, changes up via onChange (controlled components).
Q5.Why should we use <Fragment> (or <>) instead of a <div> wrapper, and how does this impact the DOM tree and CSS selectors like flexbox?
<Fragment> (or <>) instead of a <div> wrapper, and how does this impact the DOM tree and CSS selectors like flexbox?A Fragment lets a component return multiple children without adding an extra DOM node, whereas a wrapper <div> injects a real element into the tree. Avoiding that node keeps the DOM clean and, crucially, doesn't break parent layout like flexbox or grid.
The problem with wrapper divs:
They bloat the DOM with meaningless nesting, hurting readability and sometimes performance.
They break CSS relationships: in display: flex or grid, only direct children are flex/grid items, so an extra div makes your real items grandchildren and they stop being laid out.
Direct-child selectors (> *) and structural rules can also silently fail.
How Fragment helps:
It groups children for React's return requirement but renders nothing to the DOM, preserving the parent-child structure CSS expects.
Shorthand <>...</> is the common form; use the full <Fragment> when you need a key (e.g. mapping lists).
Q6.What is the difference between State and Props in React?
Props are read-only inputs passed from a parent to configure a component; state is private, mutable data a component owns and manages over its lifetime. Props flow down and can't be changed by the receiver; state changes internally and triggers re-renders.
Props:
Passed in by the parent; immutable from the child's perspective.
Make components reusable and configurable, like function arguments.
State:
Declared and owned inside the component (via useState); private to it.
Updated with a setter, which schedules a re-render; never mutate it directly.
Relationship:
A parent's state is often passed down as a child's props, so updating state cascades new props downward.
Both, when changed, cause re-renders; the difference is ownership and mutability.
Quick test: "Can the component change it itself?" Yes is state, no is props.
Q7.What is JSX, and what does it actually compile to?
JSX, and what does it actually compile to?JSX is a syntax extension for JavaScript that lets you write HTML-like markup inside JS; it's not understood by browsers, so a compiler (Babel or the TypeScript compiler) transforms it into plain function calls.
It compiles to function calls, not strings:
Classic runtime: each element becomes React.createElement(type, props, ...children).
New JSX transform (React 17+): compiles to _jsx() / _jsxs() imported automatically from react/jsx-runtime, so you no longer need import React in scope.
The output is a plain object (a React element): It describes what to render (type, props, key); it's a lightweight description, not actual DOM.
Practical consequences:
Because it's JS, you embed expressions with {} and attributes become camelCase props (className, onClick).
A component must return a single root (or a Fragment) because each createElement call returns one node.
Q8.Why must we always start Component names with a capital letter in JSX?
JSX?Capitalization is how JSX tells the difference between a built-in DOM tag and your component: lowercase names compile to string types (HTML elements) while capitalized names compile to references to a variable (your component).
Lowercase becomes a string: <div> compiles to createElement("div"), treated as a literal HTML tag.
Capitalized becomes an identifier: <MyComp> compiles to createElement(MyComp), referencing the component in scope.
The failure mode: A lowercase custom name like <myComp> is sent as the string "myComp", which React tries to render as an unknown DOM tag and your component never runs.
Workaround for dynamic types: Assign to a capitalized variable first (const Tag = condition ? A : B; then <Tag />).
Q9.What is the difference between a class component and a function component, and why has the community largely shifted to function components?
Both produce the same kind of UI, but class components use ES6 classes with lifecycle methods and this.state, while function components are plain functions that use Hooks for state and side effects; the community shifted to function components because Hooks make logic simpler, more reusable, and free of this confusion.
Class components:
State in this.state, updated with this.setState; behavior split across lifecycle methods (componentDidMount, componentDidUpdate, componentWillUnmount).
Require binding this and scatter related logic across different methods.
Function components:
State and effects via useState, useEffect, etc.; no this.
Related logic stays together in one effect rather than being split by lifecycle.
Why the shift:
Custom Hooks let you extract and reuse stateful logic, which HOCs and render props did awkwardly.
Less boilerplate, easier to read, and the direction new React features (concurrent features, Server Components) target.
Caveat: Class components are still supported; only componentDidCatch error boundaries currently require a class.
Q10.What are the different ways to conditionally render content in JSX, and what are the pitfalls of using short-circuit evaluation with values like 0?
JSX, and what are the pitfalls of using short-circuit evaluation with values like 0?Since JSX embeds JS expressions, you conditionally render with the same tools you'd use for any value: ternaries, logical &&, early returns, or variables; the main pitfall is short-circuiting on a falsy value like 0, which React actually renders.
Common techniques:
Ternary: {isOn ? <A /> : <B />} when you need an either/or.
Logical AND: {show && <A />} to render or render nothing.
Early return in the function body for whole-component branches.
Assigning JSX to a variable, then using it, to keep return readable.
The 0 pitfall:
In {count && <List />}, if count is 0, the expression evaluates to 0, and React renders the number 0 rather than nothing.
React skips true, false, null, undefined but not numbers or empty strings in some cases.
The fix: Coerce to a boolean: {count > 0 && <List />} or {!!count && <List />}.
Q11.How does the children prop work, and how does it enable component composition?
children prop work, and how does it enable component composition?children is a special prop that holds whatever you nest between a component's opening and closing tags; it lets a component render content it doesn't know about ahead of time, which is the foundation of composition.
How it's passed:
Anything between tags (<Card>...</Card>) arrives as props.children; the component decides where to place it.
It can be text, elements, an array, or even a function (render-prop pattern).
Why it enables composition: A generic wrapper (Card, Modal, Layout) provides structure/styling while the caller supplies the contents, favoring composition over inheritance.
Useful helpers:
React.Children.map and React.Children.toArray safely iterate children that may be a single node or an array.
You can also pass elements via named props ("slots") when you need multiple insertion points.
Q12.How do the three forms of the useEffect dependency array (no array, empty array, populated array) differ in terms of when the effect runs?
useEffect dependency array (no array, empty array, populated array) differ in terms of when the effect runs?The dependency array controls how often the effect re-runs after each render: no array means every render, an empty array means once, and a populated array means only when one of those values changes.
No array (useEffect(fn)): Runs after every render, cleanup before each re-run. Rarely what you want.
Empty array (useEffect(fn, [])): Runs once after mount, cleanup on unmount. Good for one-time setup.
Populated array (useEffect(fn, [a, b])): Runs after mount and again whenever a or b change (compared with Object.is).
Caveat: dependencies should be exhaustive; an empty array that uses changing values produces stale closures.
Q13.What is the purpose of "Keys" in lists, and what happens if you use a random value or an index as a key?
Keys give each list item a stable identity so React can match elements between renders and reconcile efficiently: it knows which items were added, removed, or reordered rather than rebuilding everything.
Purpose: identity, not order: Keys should be stable, unique IDs tied to the data (e.g. a database id), so the same item keeps the same key across renders.
Random keys (e.g. `Math.random()`): A new key every render makes React think every item is brand new: it unmounts and remounts all of them, destroying state and DOM, killing performance.
Index as key:
Fine only for static lists that never reorder, insert, or delete.
On reorder/insert, the index stays the same while the data shifts, so React reuses the wrong element: state and uncontrolled input values get bound to the wrong row.
Q14.What does useContext do, and how does a component subscribe to and re-render on context changes?
useContext do, and how does a component subscribe to and re-render on context changes?useContext reads the current value of a context object and subscribes the calling component to that context: when the nearest matching Provider's value changes, every consuming component re-renders.
What it does:
Lets a component read shared data without prop drilling: const value = useContext(MyContext).
Returns the value of the nearest <MyContext.Provider> above it (or the default if none).
How subscription works:
Calling useContext registers the component as a consumer of that context.
When the Provider's value changes (by Object.is comparison), React schedules a re-render of all consumers, bypassing React.memo and shouldComponentUpdate.
The re-render trap:
Passing a fresh object/array literal as value each render makes every consumer re-render; memoize it with useMemo.
Context has no built-in selector: consumers re-render even if they only use part of the value. Split into multiple contexts to limit this.
Q15.What is the overall purpose of Strict Mode in React, and what does wrapping your app in it accomplish?
Strict Mode in React, and what does wrapping your app in it accomplish?Strict Mode is a development-only tool that helps you find unsafe patterns and side-effect bugs early. Wrapping your app (or part of it) in <StrictMode> adds extra checks and warnings but renders nothing and has no effect in production.
Double-invokes certain functions: Render functions, state updaters, and effects run twice in development to surface impure logic and missing effect cleanup.
Flags deprecated/unsafe APIs: Warns about legacy lifecycle methods, legacy string refs, and other patterns that won't work well with concurrent features.
Prepares for concurrent rendering: By exposing non-idempotent code, it ensures components tolerate React mounting, unmounting, and re-running them.
Dev-only: No extra behavior or double-invocation in production builds; it's purely a safety net during development.
Q16.Explain the difference between the Virtual DOM and the real DOM, and why is the Virtual DOM considered a performance optimization?
Virtual DOM and the real DOM, and why is the Virtual DOM considered a performance optimization?The real DOM is the browser's live tree of nodes; the Virtual DOM is a lightweight JavaScript object representation of that tree. React diffs Virtual DOM versions and applies only the minimal necessary real DOM updates, which is where the optimization comes from.
Real DOM:
Direct mutations are expensive: they can trigger layout reflow, style recalculation, and repaint.
Manually doing many small updates often causes redundant, badly batched work.
Virtual DOM:
A plain in-memory tree of elements, cheap to create and compare.
On state change React builds a new tree, diffs it against the previous one (reconciliation), and computes the smallest set of real DOM operations.
Why it's a performance optimization:
It batches and minimizes costly DOM writes, avoiding redundant reflows.
Nuance: the VDOM isn't faster than perfectly hand-optimized DOM code; its real win is giving you a simple declarative model while keeping updates reasonably efficient.
Q17.How does useRef differ from useState, and when should you use a ref instead of state?
useRef differ from useState, and when should you use a ref instead of state?Both persist values across renders, but useState triggers a re-render when its value changes while useRef holds a mutable value that does not cause re-renders. Use a ref for data the UI does not need to display.
useState drives the UI:
Calling the setter schedules a re-render so the screen reflects the new value.
State is treated as immutable: you replace it, you don't edit it in place.
useRef is a mutable box:
Returns { current: value }; assigning to .current mutates it without scheduling a render.
The same object identity is preserved for the component's whole lifetime.
Use a ref when:
You need a DOM node (ref={inputRef}) to focus, measure, or scroll.
You store instance-like values the render doesn't show: timer IDs, previous values, mutable counters.
Rule of thumb: if changing the value should update the screen, use state; otherwise use a ref.
Q18.Explain the difference between a controlled and an uncontrolled component, and in what scenario would you prefer an uncontrolled component?
A controlled component's value is driven by React state (single source of truth), while an uncontrolled component keeps its own value in the DOM and you read it only when needed via a ref.
Controlled:
Value comes from state and an onChange handler writes every keystroke back: value={x} onChange={...}.
Enables instant validation, conditional disabling, and formatting as the user types.
Uncontrolled:
The DOM holds the value; you grab it with a ref (inputRef.current.value) or on submit, using defaultValue for the initial value.
Less re-rendering and less code for simple forms.
Prefer uncontrolled when:
A simple form only needs values at submit time and no per-keystroke logic.
File inputs, which are inherently uncontrolled (<input type="file">).
Integrating with non-React/third-party DOM code.
Q19.When would you choose useReducer over useState, and what are the architectural trade-offs?
useReducer over useState, and what are the architectural trade-offs?Reach for useReducer when state is complex or when the next state depends on the current one through many distinct actions; it centralizes update logic in one pure function instead of scattered setter calls.
Choose useReducer when:
Multiple sub-values change together or transitions are interdependent (e.g. a wizard, a cart).
You have many event types: a dispatch({type}) reads clearer than several setState calls.
Architectural trade-offs:
Pro: the reducer is a pure function, so transitions are testable and predictable in one place.
Pro: dispatch is stable, so passing it down avoids re-renders and breaks dependency churn.
Con: more boilerplate (actions, reducer); overkill for one or two simple values.
Rule of thumb: independent simple values, useState; structured state with rich transitions, useReducer.
Q20.Why must state be treated as immutable in React, and what happens if you mutate state directly instead of using a setter function?
React decides whether to re-render by comparing the new state reference to the old one (Object.is). Mutating state in place keeps the same reference, so React sees no change and may skip the re-render, leaving the UI stale and bugs hard to trace.
Why immutability matters:
Re-renders are triggered by a new reference; arr.push(x) mutates the existing array so the reference is unchanged.
Bail-out optimizations (React.memo, useMemo) rely on reference equality and break under mutation.
What goes wrong if you mutate:
The screen doesn't update even though the data changed.
You can corrupt prior state used by StrictMode double-invokes or concurrent features.
Do this instead: create a new value: Use spreads or array methods that return copies (map, filter, spread).
Q21.How does React handle state updates that are dependent on the previous state, and why is the functional update pattern preferred?
When the next state depends on the previous, pass a function to the setter (setCount(c => c + 1)) instead of a value. React queues updates and applies functional updaters against the latest state, so you avoid stale-closure bugs from batching.
The problem with value updates:
State is a constant within a render; setCount(count + 1) twice reads the same stale count and only increments once.
React batches multiple updates in one event, so the closed-over value is outdated.
Why the functional form is preferred:
Each updater receives the most recent pending state, so queued updates compose correctly.
It avoids needing the current state in the dependency array of effects/callbacks.
Q22.What happens if you update state inside a render function or the body of a function component?
Calling a setter directly during render causes an infinite render loop: the update schedules another render, which sets state again, and so on. React detects this and throws "Too many re-renders." State updates belong in event handlers or effects, not in the render path.
Why it loops: Render must be a pure function of props and state; setting state is a side effect that triggers re-render, repeating forever.
Where state updates should go:
Event handlers (onClick, onChange) in response to user actions.
Effects (useEffect) for updates triggered by render results, like syncing to props.
Legitimate exception:
A conditional setState during render to derive state from props is allowed if guarded (e.g. if (x !== prev) setX(x)); React restarts the render without committing, avoiding the loop.
Usually it's cleaner to compute the value during render instead of storing it.
Q23.How do you decide whether a piece of data should be managed as state or passed as props, and what are the conceptual trade-offs?
Ask who owns the data: if a component creates and mutates it over time, it's state; if a component only receives and reads it from a parent, it's props. State is local and writable; props are passed down and read-only.
Make it state when:
The value changes over time due to user interaction or async events (input text, toggles, fetched data).
No parent already has it, and this component is the natural owner.
Make it props when:
The data is owned elsewhere and this component just displays or forwards it.
It can be derived from existing state/props (compute it during render instead of storing it).
Trade-offs:
Lifting state up: shared data lives in the closest common ancestor and flows down as props, keeping a single source of truth.
Too much local state causes duplication and sync bugs; too much lifting causes prop drilling and re-renders.
Rule of thumb: minimize state, derive the rest. Store only what can't be computed from other values.
Q24.What is the difference between a callback ref and a ref object created with useRef, and when would you use a callback ref?
useRef, and when would you use a callback ref?A useRef object is a stable container ({ current }) React fills with the DOM node; a callback ref is a function React calls with the node when it mounts and with null when it unmounts. Use a callback ref when you need to run logic exactly at attach/detach time.
Ref object (useRef):
Identity is stable across renders; React assigns the node to ref.current.
Best for simply reading or imperatively calling a DOM node later (focus, measure on demand).
Callback ref:
You control what happens: React invokes it with the node on mount and null on unmount.
Lets you react the instant a node appears: measure it, attach observers, or store it in state.
When to choose a callback ref:
Need to run setup/teardown tied to the node's lifecycle.
The element is conditionally rendered or in a list and you must track when it mounts.
Caveat: an inline arrow callback runs on every render (null then node); use useCallback if that matters.
Q25.What are Synthetic Events in React, and why does React use its own event system instead of native browser events?
A Synthetic Event is React's cross-browser wrapper around the native DOM event, exposing the same interface (preventDefault, stopPropagation) consistently everywhere. React uses it to normalize browser differences and to manage event handling through a single delegated system.
What it is: A wrapper object with a normalized API identical across browsers; e.nativeEvent still exposes the raw event.
Why React uses its own system:
Consistency: smooths over browser quirks so handlers behave the same everywhere.
Performance via delegation: React attaches listeners at the root (the app container in React 17+) instead of on every node.
Integration: events flow through React's render/batching model, so state updates from handlers batch together.
Practical notes:
Handlers are camelCase (onClick) and take a function, not a string.
In React 17+ pooling was removed, so you can safely read the event asynchronously (older versions required e.persist()).
Q26.Why does React favor composition over inheritance, and what does a compositional architecture look like?
React favors composition because UI is naturally built by combining small components, not by extending base classes. Instead of inheriting behavior, you assemble it: pass components and data through props and children to build richer components from simpler ones.
Why not inheritance:
Deep class hierarchies are rigid: behavior reuse across unrelated components doesn't fit a single inheritance chain.
Components rarely have an "is-a" relationship; they have a "contains/uses" relationship, which composition models directly.
What composition looks like:
Containment: generic components (Card, Modal) render whatever you pass via children or named-slot props.
Specialization: a specific component renders a generic one with preset props (a WelcomeDialog rendering Dialog).
Logic reuse: custom hooks share stateful behavior without touching the component tree.
Payoff: flexible, decoupled components you can mix freely, avoiding fragile base-class coupling.
Q27.What are "Pure Components" and how do they relate to functional programming?
A pure component renders the same output for the same props and state and has no side effects during render; this mirrors a pure function in functional programming, which makes rendering predictable and skippable when inputs haven't changed.
The functional-programming link: A pure function: same inputs produce same output, no mutation of external state. A React component should treat props and state as immutable inputs and just compute UI.
How React expresses it:
Class: React.PureComponent implements shouldComponentUpdate with a shallow props/state comparison.
Function: React.memo() wraps a component to skip re-render when props are shallowly equal.
Why purity pays off: Enables bailing out of re-renders (memoization) safely, and is required for features like Strict Mode double-invoking and concurrent rendering.
The shallow-comparison caveat: New object/array/function props each render defeat the optimization; stabilize them with useMemo / useCallback.
Q28.What is the primary benefit of a custom hook over a standard helper function, and how do they interact with React's stateful logic?
The key difference is that a custom hook can call other hooks (useState, useEffect, etc.), so it encapsulates stateful, lifecycle-aware logic, while a plain helper function cannot. This lets you reuse behavior, not just compute values.
A helper function is stateless: It can only transform inputs to outputs; it cannot hold state across renders or subscribe to effects.
A custom hook taps into React's machinery:
By convention named useSomething, it may call built-in hooks and therefore manage state, side effects, and refs.
It participates in the component's render/lifecycle just as if the logic lived inline.
State is per-call, not shared: Each component that calls the hook gets its own isolated state; the hook shares logic, not data.
It must obey the Rules of Hooks: Call it at the top level of a component or another hook, never conditionally.
Q29.Why can't you use async functions directly inside a useEffect?
async functions directly inside a useEffect?Because making the effect callback itself async changes its return value: an async function always returns a Promise, but React expects the effect to return either nothing or a cleanup function. You instead define an async function inside the effect and call it.
The return type conflict: React reads the return value as a cleanup function; a returned Promise is not callable as cleanup, so cleanup breaks.
The correct pattern: Declare an async function inside and invoke it, or use an IIFE.
Handle stale results: Use a cancelled flag or AbortController in cleanup so a late response doesn't update an unmounted or outdated component.
Q30.What are the main lifecycle methods of a class component, and what are their equivalents using Hooks in a function component?
Class components have distinct mounting, updating, and unmounting methods; in function components a single useEffect (plus useState) covers most of them by varying its dependency array and cleanup.
Mounting:
constructor (initial state) maps to useState / useReducer.
componentDidMount maps to useEffect(fn, []).
Updating:
componentDidUpdate maps to useEffect(fn, [deps]) running when deps change.
shouldComponentUpdate maps to React.memo for the component.
Unmounting: componentWillUnmount maps to the cleanup function returned from useEffect.
Other equivalents:
getDerivedStateFromError / componentDidCatch have no hook yet (error boundaries still require classes).
For synchronous DOM measurements use useLayoutEffect instead of useEffect.
Q31.What is the purpose of the cleanup function returned from useEffect, and when exactly does React run it?
useEffect, and when exactly does React run it?The cleanup function undoes whatever the effect set up (subscriptions, timers, listeners) to prevent leaks and stale work. React runs it before the effect runs again and once more when the component unmounts.
What it's for: Tear down side effects: clearInterval, remove event listeners, close sockets, cancel subscriptions or requests.
When React runs it:
Before re-running the effect on a dependency change (cleans up the previous effect first).
When the component unmounts.
Why the order matters: Each effect's cleanup closes over its own render's values, so the right subscription is torn down before a new one is created.
Note: in development with Strict Mode, React intentionally mounts, cleans up, then remounts to surface missing cleanup.
Q32.What are the Rules of Hooks, and why does React enforce that hooks are called at the top level in the same order every render?
The Rules of Hooks are: only call hooks at the top level (not inside conditions, loops, or nested functions), and only call them from React function components or other hooks. React relies on a consistent call order each render to match each hook to its stored state.
The two rules:
Call hooks at the top level, in the same order every render.
Call hooks only from React functions (components or custom hooks).
Why order matters:
React stores hook state in an ordered list by call index, not by name; it has no labels to match them.
A conditional hook shifts the indices, so React would hand a hook the wrong state.
Enforcement: eslint-plugin-react-hooks catches violations at lint time.
Workaround: put the condition inside the hook, not the hook inside the condition (useEffect(() => { if (x) ... })).
Q33.What is the difference between useMemo and useCallback, and when is it over-optimization to use them?
useMemo and useCallback, and when is it over-optimization to use them?Both memoize across renders by dependencies, but useMemo caches a computed value while useCallback caches a function reference. They're over-optimization when the work is cheap or the memoized result isn't actually relied on for referential stability.
useMemo: Returns the result of a calculation, recomputing only when deps change. Use for genuinely expensive computations or to keep an object/array reference stable.
useCallback:
Returns a memoized function. useCallback(fn, deps) is equivalent to useMemo(() => fn, deps).
Main use: pass a stable callback to a React.memo child or as another hook's dependency.
When it's over-optimization:
Memoizing trivial math or strings: the comparison and cache cost more than the work saved.
Memoizing a callback whose consumer isn't memoized, so the stable reference buys nothing.
They add memory and complexity; profile before reaching for them.
Q34.Explain the concept of code splitting in React using React.lazy and Suspense, and how does it improve Time to Interactive?
React.lazy and Suspense, and how does it improve Time to Interactive?Code splitting breaks your bundle into smaller chunks loaded on demand. React.lazy defers loading a component's code until it renders, and Suspense shows a fallback while that chunk downloads, so the initial bundle is smaller.
React.lazy turns a dynamic import into a component: It takes a function returning import('./X'), so that code ships as a separate chunk fetched only when needed.
Suspense handles the loading state: Wrap the lazy component in <Suspense fallback={...}> to render a spinner while the chunk loads.
Improves Time to Interactive (TTI):
Less JS to parse, compile, and execute up front means the main thread is free sooner and the page becomes interactive faster.
Defer routes, modals, or heavy widgets that aren't needed on first paint.
Caveat: split at meaningful boundaries (routes, large features), not everywhere, or excessive request overhead hurts.
Q35.How does React.memo work, and how does it differ from useMemo?
React.memo work, and how does it differ from useMemo?React.memo is a higher-order component that memoizes a component, skipping re-render when its props are unchanged (shallow comparison). useMemo is a hook that memoizes a computed value inside a component. One caches a rendered component; the other caches a value.
React.memo wraps a component:
On re-render of the parent, it shallow-compares new props to old; if equal, it reuses the previous render output.
Accepts an optional second arg, a custom comparison function.
useMemo caches a value: Recomputes only when its dependency array changes; useful for expensive calculations or stable object/array references.
They work together: Use useMemo (or useCallback) to keep prop references stable so a React.memo child actually benefits.
Q36.How does React.memo optimize performance, and what is the difference between a shallow comparison and a deep comparison in this context?
React.memo optimize performance, and what is the difference between a shallow comparison and a deep comparison in this context?React.memo skips re-rendering a component when its props haven't changed, deciding via a shallow comparison by default. Shallow checks only top-level reference/primitive equality; a deep comparison would recursively compare nested values.
How it optimizes: When the parent re-renders, React.memo compares previous and next props; if equal, it reuses the last render and skips the subtree.
Shallow comparison:
Compares each prop one level deep: primitives by value, objects/arrays/functions by reference.
A new object with identical contents fails the check because the reference differs.
Deep comparison:
Recursively compares nested structure; correct for changed-by-content props but potentially expensive.
You can supply a custom comparator as React.memo's second argument, but a costly deep compare can outweigh the render it saves.
Best practice: keep props referentially stable so the cheap shallow check suffices.
Q37.How do you identify a performance bottleneck in a React application?
Identify bottlenecks by measuring, not guessing: use the React DevTools Profiler and browser performance tools to find what's slow (rendering, JavaScript, or network), then drill into the specific cause.
React DevTools Profiler:
Records commits and shows render durations and which components re-rendered and why.
Flamegraph highlights the most expensive components in a commit.
Browser tools:
Chrome Performance tab for long tasks, scripting time, and main-thread blocking.
Lighthouse / Web Vitals for TTI, LCP, and bundle-size issues.
Categorize the cause:
Rendering: too-frequent or too-broad re-renders, huge lists.
Compute: expensive calculations on the main thread.
Network/bundle: large initial JS, unsplit code.
Always measure before and after a fix to confirm the change actually helped.
Q38.What is virtualization (or windowing), and why is it necessary for rendering large datasets?
Virtualization (windowing) renders only the items currently visible in the viewport (plus a small buffer) instead of the entire dataset, swapping items in and out as the user scrolls. It's necessary because rendering thousands of DOM nodes is expensive in both memory and render time.
How it works:
Calculates which items fall in the visible window based on scroll position and item size.
Mounts only those, using a sized spacer/container so the scrollbar reflects the full list height.
Why it's needed:
Each DOM node costs memory and layout/paint work; thousands of rows tank scroll performance and TTI.
Keeps the DOM size roughly constant regardless of dataset size.
Tooling: Libraries like react-window and react-virtualized handle the math and recycling.
Tradeoffs: variable item heights and accessibility/search (Ctrl+F won't find off-screen rows) need extra care.
Q39.When is the Context API the right choice versus simply drilling props, and what are the performance pitfalls of overusing Context?
Context API the right choice versus simply drilling props, and what are the performance pitfalls of overusing Context?Use Context when truly shared, slowly-changing data would otherwise be drilled through many intermediate layers that don't use it; prefer prop drilling for shallow or localized passing. The main pitfall is that every consumer re-renders when the Context value changes.
Prop drilling is fine when: The path is short (one or two levels) and the data is explicit: it's more readable and traceable than hidden context.
Context is right when: Data is genuinely global and stable: theme, current user, locale, auth: passed deep through unrelated components.
Performance pitfalls:
Any change to the provider value re-renders all consumers, even ones reading an unrelated part of it.
Inline object values (`value={{ user, setUser }}`) create a new reference each render, forcing consumer re-renders: memoize the value.
Mitigate by splitting into multiple narrow contexts and keeping fast-changing state out of widely-consumed context.
Q40.What is the Context API, and does it replace a dedicated state management library?
Context API, and does it replace a dedicated state management library?The Context API is React's built-in way to share a value with a component subtree without passing props through every level: a `Provider` supplies the value and any descendant reads it with `useContext`. It's a dependency-injection tool, not a full state manager, so it doesn't automatically replace libraries like Redux.
What Context provides: Value distribution to avoid prop drilling: it has no built-in reducers, middleware, selectors, or optimized partial subscriptions.
Where libraries add value: Tools like Redux, Zustand, or Jotai offer fine-grained subscriptions (re-render only the parts that changed), devtools, middleware, and structured update patterns.
The key limitation: Context re-renders all consumers on any value change, so for large, frequently-updated state a dedicated store is more efficient.
Practical take: Context plus `useReducer` handles modest app state; reach for a library when state is large, fast-changing, or needs advanced tooling.
Q41.What are Error Boundaries, why can they only be implemented as Class Components, and what types of errors do they not catch?
Error Boundaries are components that catch JavaScript errors thrown during rendering, in lifecycle methods, and in constructors of their child tree, then render a fallback UI instead of crashing the whole app. They must be classes because the catching mechanism relies on lifecycle methods that have no Hook equivalent.
How they work:
static getDerivedStateFromError() updates state to show fallback UI.
componentDidCatch(error, info) is for side effects like logging.
Why class-only: React provides no Hook that replicates getDerivedStateFromError/componentDidCatch, so a class is currently the only way to author one.
What they do NOT catch:
Errors inside event handlers (use a regular try/catch).
Asynchronous code (setTimeout, promises, fetch callbacks).
Server-side rendering errors.
Errors thrown in the boundary itself (only its children).
Q42.When would you use ReactDOM.createPortal, and can you explain a scenario where the DOM hierarchy needs to differ from the React component hierarchy?
ReactDOM.createPortal, and can you explain a scenario where the DOM hierarchy needs to differ from the React component hierarchy?ReactDOM.createPortal renders children into a DOM node that lives outside the parent component's DOM subtree, while keeping them in the React tree for state, context, and event bubbling. You use it when CSS containment (overflow, z-index, stacking context) would otherwise clip or trap an element.
Signature: createPortal(children, domNode): renders children into domNode (often appended to document.body).
Why DOM and React hierarchy diverge:
A modal declared deep inside a card with overflow: hidden or a low z-index would be clipped; portaling it to body escapes that stacking context.
Logically it's still a child, so it keeps its props, state, and context.
Key behavior: Events bubble through the React tree (the parent), not the DOM location: a click in the portal reaches handlers on the React ancestor.
Common uses: modals, tooltips, dropdowns, toasts.
Q43.What are "Higher-Order Components" (HOCs) and why have they become less common since the introduction of Hooks?
A Higher-Order Component is a function that takes a component and returns a new component with added behavior or props: a pattern for reusing logic across components. They've become less common because custom Hooks share the same logic without wrapping components.
Definition:
const Enhanced = withAuth(MyComponent): the HOC injects props or wraps rendering logic.
Examples from libraries: connect() (Redux), withRouter().
Why they're less common now:
Wrapper hell: nested HOCs bloat the component tree and devtools.
Prop collisions and unclear prop origins.
Need to forward refs and hoist static methods manually.
Hooks share the same logic via a function call (useAuth()) with no extra nesting.
Still useful occasionally: cross-cutting concerns applied to many components, or wrapping third-party class components.
Q44.Explain the "Render Props" pattern.
The Render Props pattern shares code between components by passing a function as a prop that returns React elements: the component owning the logic calls that function with its internal state, letting the consumer decide what to render.
Mechanics:
A component exposes its state by invoking a function prop instead of rendering fixed UI.
Often the function is passed as children rather than a named prop.
Why it's flexible: Separates the "how to get data" (the logic component) from "how to display it" (the consumer).
Drawback: nesting multiple render props creates a hard-to-read pyramid; custom Hooks now cover most cases.
Q45.What is the difference between useEffect and useLayoutEffect, and when would using the former cause a flicker in the UI?
useEffect and useLayoutEffect, and when would using the former cause a flicker in the UI?Both run side effects after render, but useEffect fires asynchronously after the browser paints, while useLayoutEffect fires synchronously after DOM mutations but before paint. Use the layout version when you must measure or mutate the DOM before the user sees it, to avoid a visible flicker.
useEffect:
Runs after paint, non-blocking: best for data fetching, subscriptions, logging.
Doesn't delay the visual update.
useLayoutEffect:
Runs before paint, blocking: read layout (getBoundingClientRect) and apply DOM changes synchronously.
Overuse hurts performance since it blocks painting.
When useEffect flickers:
If the effect reads the DOM and then sets state that changes position/size (e.g. positioning a tooltip), the user briefly sees the pre-adjustment frame, then a corrected one.
Moving that measurement to useLayoutEffect applies the fix before paint, eliminating the flash.
Q46.Why does React's 'Strict Mode' double-invoke effects and reducers in development, and what kind of bugs is it trying to surface?
In development, Strict Mode intentionally double-invokes certain functions (component render bodies, effects via mount/unmount/remount, and reducers) to surface code that isn't pure or doesn't clean up properly. It's a dev-only check and never runs twice in production.
What gets double-invoked:
Component and useState/useReducer initializer functions, plus reducers, are called twice.
Effects run setup, then cleanup, then setup again to simulate a remount.
Bugs it surfaces:
Impure renders: mutating props/state or external variables during render shows up as inconsistent output.
Missing effect cleanup: subscriptions, timers, or listeners that aren't torn down cause duplicates or leaks, which the mount/unmount/remount makes obvious.
Side effects living in render or reducers (which must be pure).
Why it matters: Forces idempotent, side-effect-free renders, which makes components resilient to future features like reusable state and concurrent rendering.
Q47.What is useId used for, and why can't you just use a random number or index to generate IDs?
useId used for, and why can't you just use a random number or index to generate IDs?useId generates a unique, stable ID that is consistent between server and client renders, primarily for accessibility attributes that link elements (like a label to its input). A random number breaks because it differs between the server-rendered HTML and the client hydration, causing a mismatch.
Stable across renders: The ID stays the same on every re-render, unlike Math.random() which produces a new value each time.
SSR/hydration safe: Server and client generate identical IDs, avoiding hydration mismatch warnings. A random value would differ between the two environments.
For accessibility, not keys: Meant for id/htmlFor/aria-* attributes, not for list key props (use your data's IDs for those).
Q48.What exactly causes a React component to re-render, and does a parent re-rendering always cause all children to re-render?
A component re-renders when its state changes, its parent re-renders, or a context it consumes changes. And yes, by default a parent re-rendering causes all of its children to re-render, regardless of whether their props changed, unless you intervene with memoization.
Triggers of a re-render:
A state update via useState/useReducer.
The parent re-rendering (new props or not).
A consumed context value changing.
Parent renders cascade by default: React re-renders the whole subtree; re-rendering doesn't necessarily mean DOM changes (the diff may produce no updates), but the component functions still run.
How to stop unnecessary child renders:
Wrap the child in React.memo so it only re-renders when its props actually change.
Stabilize prop references with useMemo/useCallback so memoization holds.
Common myth: Changing a prop value is not what triggers a child's render; the parent rendering is. Props just feed the comparison.
Q49.Explain the reconciliation process: how does React's diffing algorithm decide which parts of the DOM to update?
DOM to update?Reconciliation is the process React uses to compare the new element tree against the previous one and figure out the minimal set of DOM operations needed. Because a perfect tree diff is expensive, React uses a heuristic O(n) algorithm based on a few practical assumptions.
Different element types = full replace: If the type changes (e.g. <div> to <span>), React tears down the old node and subtree and builds a new one.
Same type = update in place: React keeps the DOM node, updates only changed attributes/props, then recurses into children.
Lists use keys:
Keys let React match elements between renders so it can reorder, insert, or remove items instead of rebuilding the list.
Using array index as a key can cause bugs when items reorder or are inserted/removed.
Heuristic, not exhaustive: React doesn't try to find the globally minimal diff; the type and key assumptions keep it fast and good enough in practice.
Q50.What is the "Virtual DOM" and how does the "Diffing Algorithm" work?
The Virtual DOM is a lightweight in-memory JavaScript representation of the UI. React renders to this virtual tree, and the diffing algorithm compares the new tree with the previous one to compute the minimal real DOM changes, since direct DOM manipulation is slow.
Virtual DOM:
A tree of plain JS objects describing what the UI should look like; cheap to create and compare versus touching the real DOM.
On each render React builds a new virtual tree and reconciles it against the old one.
Diffing algorithm:
Compares two trees node by node using heuristics for O(n) performance.
Different element type: replace the node and its subtree.
Same type: keep the node, patch only the changed props/attributes.
Lists: use key props to match, reorder, and reuse elements efficiently.
Result: React batches the computed differences and applies them to the real DOM in one commit, minimizing expensive layout/reflow work.
Q51.What does the 'use client' directive actually do? Does it mean the component only renders on the client?
'use client' directive actually do? Does it mean the component only renders on the client?'use client' marks the boundary where the module graph switches from Server Components to Client Components: it doesn't mean "client-only," it means this component (and its imports) ships JS to the browser and can use interactivity. It still typically renders once on the server for the initial HTML, then hydrates on the client.
It's a boundary marker, not a runtime switch: Placed at the top of a file, it opts that module and everything it imports into the client bundle.
It enables client-only features: Hooks like useState/useEffect, event handlers, and browser APIs are only allowed past this boundary.
It still runs on the server too: During SSR the client component renders to HTML for fast first paint, then hydrates in the browser. "Client" describes where it becomes interactive, not where it first renders.
It's inherited downward: You only need it once at the top of a subtree; imported children become client components automatically.
Server Components are the default: Without the directive, components stay server-side, send no JS, and can directly access server resources.
Q52.Why is it now recommended to fetch data directly inside Server Components rather than using useEffect on the client?
useEffect on the client?Fetching in Server Components lets data load on the server before HTML is sent, eliminating client-side waterfalls, loading spinners, and shipped fetch code. useEffect fetching only starts after the component mounts in the browser, which is slower and more fragile.
No client-side waterfall:
useEffect fetches run only after JS downloads, parses, and the component mounts, so users see empty/loading UI first.
Server Components fetch during render and stream finished HTML.
Direct access to data sources: You can await the DB or an API directly, keeping secrets and heavy logic off the client.
Less JavaScript shipped: Fetching logic and data-handling libraries stay on the server, shrinking the bundle.
Simpler code: No loading/error state juggling; an async component just returns markup, with Suspense handling fallbacks.
When you still need useEffect: Data that depends on client-only state, user interaction, or real-time subscriptions.
Q53.Explain the concept of 'Actions' in React 19. How do they simplify form handling compared to the traditional useState and onSubmit pattern?
useState and onSubmit pattern?Actions are functions (often async) that you pass to a form's action prop or trigger via transitions; React wires up pending state, errors, and optimistic updates for you, replacing the manual useState + onSubmit plumbing.
The old pattern was manual: You tracked isLoading, error, and form values yourself, called e.preventDefault(), then updated state by hand.
Actions automate the lifecycle:
Pending state, error handling, and resetting are managed by React via transitions.
A function passed to <form action={fn}> receives FormData automatically.
Works with the new hooks: useActionState for result/pending, useFormStatus for child components, useOptimistic for instant UI.
Server or client: With Server Actions the same model submits directly to the server, even before hydration.
Q54.Why is forwardRef being deprecated in React 19, and how do we handle refs in functional components now?
forwardRef being deprecated in React 19, and how do we handle refs in functional components now?In React 19 ref is now a regular prop for function components, so the forwardRef wrapper that existed only to forward refs is no longer needed and is being deprecated to simplify the API.
Why it existed: ref used to be special and not passed through props, so forwardRef was the only way to pass a ref into a function component.
What changed: You can now declare ref directly in your props and use it like any other prop.
Migration: Remove the forwardRef wrapper and accept { ref } in the parameter list; existing forwardRef still works during the transition.
Less boilerplate: Fewer wrappers and cleaner TypeScript types for component props.
Q55.What is the difference between useActionState and useFormStatus, and when would you use one over the other?
useActionState and useFormStatus, and when would you use one over the other?useActionState manages an action's result and pending state from the component that owns the form, while useFormStatus reads the pending status of the nearest parent form from a child component without prop drilling.
useActionState:
Wraps an action and returns [state, formAction, isPending].
Use it where you define the form to hold the returned data/error and the submit handler.
useFormStatus:
Returns { pending, data, method, action } for the enclosing <form>.
Designed for reusable child components (like a submit button) that need pending state but shouldn't take props for it.
Must be called inside a component rendered within the form, not the form component itself.
When to use which:
Need the action's return value or error: useActionState.
Just need "is the form submitting?" in a nested component: useFormStatus.
Q56.How does React handle events under the hood: where does it attach event listeners, and what changed about event delegation in React 17?
React doesn't attach a listener to every DOM node; it uses event delegation, attaching a few listeners at a root container and dispatching synthetic events to your handlers. In React 17 the delegation root moved from document to the root DOM container that you render into.
Synthetic events: Your onClick gets a SyntheticEvent, a cross-browser wrapper over the native event with a consistent API.
Delegation, not per-node listeners: React listens at one root and figures out which component handler to call as the event bubbles, which is more memory-efficient.
What changed in React 17:
Listeners now attach to the root container passed to ReactDOM.render instead of document.
This makes it safe to run multiple React versions or embed React in a larger app, since e.stopPropagation() in one tree won't leak across trees.
Practical note: Event pooling (reusing the synthetic event object) was removed in React 17, so you no longer need e.persist().
Q57.Why can't hooks be called inside loops or conditions, and how does React track hook state internally using an array/linked list?
React doesn't identify hooks by name; it relies on them being called in the same order on every render, storing each hook's state in a list indexed by call order. Loops, conditions, or early returns can change that order, so React would read the wrong slot, which is why the Rules of Hooks forbid them.
How React tracks hooks:
Each component's fiber holds an ordered list (a linked list of hook objects); a cursor advances by one each time a hook is called.
On the first render it builds the list; on re-renders it walks the same list in the same order to retrieve each hook's saved state.
Why order must be stable: Position, not name, maps a call to its state. If a conditional skips a hook, every later hook shifts by one slot and reads another hook's value.
The rule:
Call hooks only at the top level of a component or custom hook, never inside loops, conditions, or nested functions.
To do something conditionally, put the condition inside the hook (e.g. inside useEffect) rather than around the hook call.
Enforcement: The eslint-plugin-react-hooks lint rule catches violations at dev time.
Q58.Explain the stale closure problem in useEffect. How does the dependency array solve this, and what happens if you omit a dependency?
useEffect. How does the dependency array solve this, and what happens if you omit a dependency?A stale closure happens when an effect (or callback) captures variables from the render in which it was created, so it keeps reading their old values instead of the latest ones. The dependency array fixes this by telling React to re-run the effect (and re-capture fresh values) whenever those dependencies change.
Why it happens:
Every render creates new functions that close over that render's props and state. An effect runs against the snapshot it was defined in.
If the effect never re-runs, it permanently sees the values from the first render.
How the dependency array solves it:
React compares each dependency (via Object.is) to the previous render; if any changed, it re-runs the effect with the new closure.
So the listed values are always current inside the effect.
If you omit a dependency:
The effect won't re-run when that value changes, so it operates on stale data (bugs like a counter stuck at its initial value).
The eslint-plugin-react-hooks exhaustive-deps rule flags missing dependencies.
Escape hatch: if you need the latest value without re-running, use a ref or the updater form setCount(c => c + 1).
Q59.How does the new React Compiler (React Forget) change how we think about performance optimization, and does it make useMemo and useCallback obsolete?
useMemo and useCallback obsolete?The React Compiler (formerly React Forget) automatically memoizes components and values at build time, so you rarely write manual memoization. It largely makes useMemo and useCallback unnecessary for performance, but it doesn't make them obsolete in every case.
What it does:
Analyzes your components and inserts fine-grained memoization automatically, caching values and re-rendering only what truly changed.
Relies on the Rules of React (purity, no mutation) to safely reason about dependencies.
Shift in mindset: You write idiomatic, readable code and let the compiler optimize, instead of manually tuning re-renders.
Does it kill useMemo/useCallback?:
For performance memoization: largely yes, the compiler covers it.
But useMemo still matters for semantic stability (e.g. a stable reference passed to a non-React API or used as an effect dependency).
Code that breaks the Rules of React won't be optimized, so manual hooks remain a fallback.
Q60.What are the performance tradeoffs of using the Context API for frequently changing values?
Context API for frequently changing values?Context triggers a re-render in every consumer whenever its value changes, regardless of whether a given consumer uses the part that changed. For frequently changing values this can cause widespread, expensive re-renders.
The core problem:
All components reading the context re-render on any value change; Context has no built-in selector to subscribe to a slice.
A new object/array passed as value each render forces consumers to re-render even if data is identical.
Mitigations:
Split contexts: separate stable data from fast-changing data so updates are scoped.
Memoize the value with useMemo to avoid identity churn.
Wrap consumers in React.memo where helpful.
When it's the wrong tool: For high-frequency updates (cursor position, form keystrokes shared widely), prefer a state library with selector-based subscriptions (Zustand, Redux, Jotai).
Q61.How do you identify and fix "wasted" or unnecessary re-renders in a large application?
Q62.What are the costs of over-using React.memo, and why shouldn't we wrap every single component in it?
React.memo, and why shouldn't we wrap every single component in it?Q63.What is the difference between useTransition and useDeferredValue, and when would you use one over the other to improve perceived performance?
useTransition and useDeferredValue, and when would you use one over the other to improve perceived performance?Q64.Explain Suspense for data fetching: how does it change the way we handle loading states compared to the traditional loading-spinner pattern?
Suspense for data fetching: how does it change the way we handle loading states compared to the traditional loading-spinner pattern?Q65.What is 'Concurrent Rendering', and how does it allow React to remain responsive during heavy UI updates?
React to remain responsive during heavy UI updates?Q66.Explain the concept of Transitions in React 18 and how useTransition helps maintain UI responsiveness during heavy re-renders.
React 18 and how useTransition helps maintain UI responsiveness during heavy re-renders.Q67.Compare the HOC pattern with the Render Props pattern, and why have both largely been replaced by Hooks?
Q68.What is the purpose of useImperativeHandle when used with forwardRef?
useImperativeHandle when used with forwardRef?Q69.What is React Fiber, and how does it differ from the old stack reconciler in terms of how it handles updates?
React Fiber, and how does it differ from the old stack reconciler in terms of how it handles updates?Q70.What is automatic batching in React 18, and how does it change the way state updates are processed compared to older versions?
Q71.Explain the difference between the Render phase and the Commit phase in the Fiber architecture, and which one is interruptible.
Fiber architecture, and which one is interruptible.Q72.Explain the difference between the Virtual DOM and the Shadow DOM. Why does React use one but not necessarily the other?
Virtual DOM and the Shadow DOM. Why does React use one but not necessarily the other?Q73.Why does React need to traverse the entire UI tree during a re-render, and what are the performance implications of this?
Q74.What is 'Hydration' in React, and why do 'Hydration Mismatch' errors occur? How does React 18/19's selective hydration improve this?
Q75.What is the fundamental difference between a Server Component and a Client Component, and why can't you use useState in a Server Component?
useState in a Server Component?Q76.Explain the difference between React Server Components and traditional Server-Side Rendering (SSR). Do they solve the same problem?
Q77.What is "Streaming SSR" and how does it improve Time to First Byte (TTFB)?
Q78.How does useSyncExternalStore help in keeping React state in sync with external data sources?
useSyncExternalStore help in keeping React state in sync with external data sources?Q79.What problem does the use hook solve, and how does it differ from standard hooks regarding where it can be called?
use hook solve, and how does it differ from standard hooks regarding where it can be called?Q80.Explain how the useOptimistic hook works. Why is it better than manually managing 'loading' and 'success' states for UI responsiveness?
useOptimistic hook works. Why is it better than manually managing 'loading' and 'success' states for UI responsiveness?