React

Core Concepts

1

What is React and what problem does it solve?

  • React is a JavaScript library for building user interfaces through a component-based model.
  • It solves the problem of efficiently updating the DOM when application state changes, using a declarative programming model — you describe what the UI should look like, React figures out how to get there.
  • Key ideas: Components, unidirectional data flow (props down, events up), and the Virtual DOM.
  • Maintained by Meta. Ecosystem includes React DOM (browser), React Native (mobile), React Three Fiber (3D).

What problems does this solve?

  • Sets the foundation for every subsequent React concept — interviewers use this to gauge how deep your mental model goes beyond just "knowing the APIs".
2

What is the Virtual DOM and how does React use it?

  • The Virtual DOM (VDOM) is an in-memory JavaScript tree that mirrors the real DOM structure.
  • When state changes, React creates a new VDOM tree, diffs it against the previous one (reconciliation), and applies only the minimal set of DOM mutations needed.
  • This is faster than rebuilding the entire DOM on every change, but the cost is the diffing computation itself.
  • React 18 introduced concurrent rendering — work can be paused, resumed, or abandoned, enabling features like Transitions and Suspense without blocking the browser.

What problems does this solve?

  • Understanding why React is fast (and when it isn't) shows architectural depth — key for senior roles.
3

What is JSX?

  • JSX is a syntax extension for JavaScript that looks like HTML but compiles to React.createElement() calls.
  • It is not required but strongly conventional in React codebases.
  • Key differences from HTML: className instead of class, htmlFor instead of for, self-closing tags required, camelCase event names (onClick, onChange).
  • Expressions are embedded with {'{}'}. JSX is an expression itself — usable in conditionals, functions, arrays.

What problems does this solve?

  • JSX is React's primary authoring syntax — understanding what it compiles to demystifies common errors.
4

What is the difference between Props and State?

  • Props: Data passed from a parent component. Read-only inside the component. Changing props triggers a re-render of the child.
  • State: Data managed internally by a component. Mutable via useState/useReducer. Changing state triggers a re-render of the component and its descendants.
  • Key rule: Components should be pure — given the same props and state, they should return the same JSX. Side effects belong in useEffect.
  • "Lifting state up" — when two sibling components need to share state, move it to their nearest common ancestor.

What problems does this solve?

  • Props vs state is the most fundamental React concept — misunderstanding it leads to bugs and anti-patterns.

Hooks

5

How does useState work?

  • useState(initialValue) returns [value, setter]. Calling the setter schedules a re-render with the new value.
  • State updates are asynchronous and batched — you won't see the new value immediately after calling the setter.
  • Use the functional updater form when the new state depends on the previous state, to avoid stale closures.

What problems does this solve?

  • The stale closure pitfall with useState is one of the most common React bugs in production — essential to understand.
6

How does useEffect work and what are its dependency rules?

  • useEffect(fn, deps) runs fn after the browser paints.
  • No deps array: Runs after every render.
  • Empty array []: Runs once after mount.
  • With deps: Runs only when any dependency changes (compared by Object.is).
  • Cleanup: Returning a function from the effect runs it before the next effect or on unmount (unsubscribe, clear timers, abort fetch).
  • React 18 Strict Mode double-invokes effects in development to surface cleanup bugs.

What problems does this solve?

  • useEffect is the most misused hook — understanding cleanup and deps is essential for avoiding memory leaks and stale data.
7

What is useRef used for?

  • useRef(initialValue) returns a mutable object {'{ current: initialValue }'} that persists across renders without triggering a re-render when changed.
  • Use case 1 — DOM access: Attach to a JSX element via the ref prop to get the underlying DOM node.
  • Use case 2 — Mutable values: Store values that need to persist but shouldn't trigger re-renders (e.g., interval IDs, previous values, instance variables).
  • Unlike state, reading ref.current inside an effect always gives the latest value (no stale closure).

What problems does this solve?

  • Refs are the escape hatch from React's declarative model — knowing when to use them vs state is an advanced signal.
8

What are useMemo and useCallback and when should you use them?

  • useMemo(fn, deps) — memoises the return value of fn. Recomputes only when deps change.
  • useCallback(fn, deps) — memoises the function reference itself. Equivalent to useMemo(() => fn, deps).
  • When to use:
    • Pass a callback to a memoised child (React.memo) to avoid unnecessary re-renders.
    • Expensive computations that would run on every render.
  • Warning: Premature optimisation — always profile first. Memoisation has its own cost (memory + comparison).

What problems does this solve?

  • useMemo/useCallback are the most over- and under-used hooks — showing measured judgment about when to apply them is a senior signal.
9

What is useContext?

  • Context provides a way to pass data through the component tree without prop-drilling.
  • Create context with createContext(defaultValue). Provide it with <Context.Provider value={'{...}'}>. Consume with useContext(MyContext).
  • Caveat: All consumers re-render when the context value changes (referential equality). Wrap values in useMemo or split contexts to avoid unnecessary re-renders.
  • Good for: theme, locale, auth, current user. Not a replacement for proper state management at scale.

What problems does this solve?

  • Context is the most commonly recommended solution for prop drilling — understanding its performance limitations shows depth.
10

What is useReducer and when do you use it over useState?

  • useReducer(reducer, initialState) returns [state, dispatch]. State transitions are handled by a pure reducer function: (state, action) => newState.
  • Use over useState when:
    • State logic is complex with multiple sub-values.
    • The next state depends on the previous state in a non-trivial way.
    • Multiple actions modify the same state — clearer to consolidate in a reducer.
  • Pairs naturally with Context to build lightweight Redux-style state management.

What problems does this solve?

  • Knowing when to upgrade from useState to useReducer shows maturity in managing complex component logic.
11

What are Custom Hooks?

  • A custom hook is a JavaScript function whose name starts with use and that calls other hooks.
  • They extract and share stateful logic between components without changing the component hierarchy (no render props or HOCs needed).
  • Examples: useFetch, useLocalStorage, useDebounce, useMediaQuery, useOnClickOutside.
  • Each call to a custom hook has its own isolated state — not shared between components unless explicitly designed that way.

What problems does this solve?

  • Custom hooks are the primary code reuse mechanism in modern React — showing you can extract and compose hooks well is a strong interview signal.
12

What is the React component lifecycle (in function components)?

  • Mount: Component rendered for the first time. useEffect(() => {'{ ... }'}, []) runs after paint.
  • Update: Re-renders when state/props change. Effects with relevant deps re-run; cleanup of previous effect runs first.
  • Unmount: Component removed from tree. Cleanup functions of all effects run.
  • Class equivalents: componentDidMount → empty-dep effect; componentDidUpdate → effect with deps; componentWillUnmount → effect cleanup.
  • Use useLayoutEffect (fires synchronously before paint) for DOM measurement; prefer useEffect for everything else.

What problems does this solve?

  • Understanding the component lifecycle is foundational for correctly using effects, avoiding memory leaks, and debugging render issues.

Patterns & Performance

13

What are Controlled and Uncontrolled Components?

  • Controlled: Form element value is driven by React state. Every keystroke updates state and React re-renders. Single source of truth.
  • Uncontrolled: Form element manages its own value in the DOM. React reads it via a ref when needed (e.g., on submit). Simpler for non-interactive forms.

What problems does this solve?

  • Form handling is one of the most common UI tasks — controlled vs uncontrolled is a foundational decision every React dev must understand.
14

What is Component Composition in React?

  • Composition is the preferred pattern for code reuse — building complex components from simpler ones rather than inheritance.
  • Children pattern: Pass JSX as children for generic container components (Modal, Card).
  • Render props: Pass a function as a prop that returns JSX, giving the parent control over what to render.
  • Compound components: A set of components that share implicit state via context (e.g., Tabs, TabPanel).
  • React explicitly recommends composition over inheritance for component hierarchies.

What problems does this solve?

  • Mastery of composition patterns is a clear senior React signal — it avoids prop-drilling and brittle inheritance chains.
15

What is React.memo and when should you use it?

  • React.memo(Component) wraps a component and skips re-rendering if props haven't changed (shallow equality by default).
  • Useful when a component is expensive to render and its parent re-renders frequently with unchanged props.
  • Pass a custom comparison function as the second argument for deep or selective comparison.
  • Pitfall: Passing a new object/array/function literal on every render defeats memoisation — pair with useMemo/useCallback.
  • Always profile before adding — memo adds overhead and complexity.

What problems does this solve?

  • React.memo is the primary tool for preventing unnecessary child re-renders — understanding when it actually helps vs hurts is critical.
16

How does React's reconciliation algorithm work and why are keys important?

  • React's reconciler (Fiber) diffs the new VDOM tree against the previous one. It assumes:
  • Elements of different types produce entirely different trees.
  • List items with stable keys can be matched across renders.
  • Keys must be unique among siblings and stable across renders (avoid using array index as key for reorderable lists).
  • Without keys, React falls back to positional matching — leading to wrong UI state when list items are reordered or removed.

What problems does this solve?

  • The key prop is one of the most common sources of subtle list-rendering bugs in React apps.
17

What are Error Boundaries?

  • Error boundaries are class components that catch JavaScript errors anywhere in their child component tree, log them, and render a fallback UI instead of crashing.
  • Implemented via static getDerivedStateFromError() and componentDidCatch().
  • They do not catch errors in: event handlers, async code, SSR, or the boundary itself.
  • Libraries like react-error-boundary provide a hook-friendly wrapper.
  • React 19 will introduce a native useErrorBoundary hook.

What problems does this solve?

  • Error boundaries are essential for production resilience — a crashed component shouldn't take down the entire app.
18

What are React Portals?

  • ReactDOM.createPortal(children, domNode) renders children into a different part of the DOM tree outside the component hierarchy.
  • Event bubbling still follows the React component tree (not the DOM tree).
  • Use cases: Modals, tooltips, dropdowns — elements that need to escape overflow: hidden or stacking context of a parent.

What problems does this solve?

  • Portals solve the common modal z-index/overflow problem cleanly without hacks — showing you know them demonstrates real-world React experience.
19

What are Suspense and lazy loading in React?

  • React.lazy(() => import('./Component')) enables code splitting at the component level — the bundle is loaded on demand.
  • <Suspense fallback={'{ }'}> shows a fallback while the lazy component loads.
  • In React 18, Suspense also works with async data fetching (via frameworks like Next.js or libraries like Relay/React Query).
  • Streaming SSR + Suspense: Allows the server to send HTML progressively as components resolve.

What problems does this solve?

  • Code splitting via Suspense is one of the most impactful performance tools in React — a must-know for any production React developer.
20

What are React Server Components (RSC)?

  • React Server Components render on the server only and are never shipped to the client as JavaScript — reducing bundle size.
  • Can directly access databases, filesystems, or server-only secrets.
  • Client Components (marked with "use client") retain interactivity, hooks, and event listeners.
  • RSC and Client Components can be interleaved — RSC can pass serialisable props to Client Components.
  • Currently primary usage is through Next.js 13+ App Router. async components are supported in RSC.

What problems does this solve?

  • RSC is the biggest architectural shift in React since Hooks — understanding the server/client boundary is essential for modern React jobs.

Ecosystem & Advanced

21

What are the main state management options in React?

  • useState / useReducer + Context: Built-in. Good for small-to-medium apps. Context has re-render caveats.
  • Zustand: Minimal, unopinionated. Simple API, good performance, no boilerplate.
  • Redux Toolkit: Structured, predictable. Best for large teams / complex state with side effects (RTK Query).
  • Jotai / Recoil: Atomic state model — fine-grained subscriptions avoid unnecessary re-renders.
  • Valtio: Proxy-based mutable state — feels imperative, React handles reactivity.
  • Server state (async data) is increasingly handled separately by TanStack Query / SWR / RTK Query.

What problems does this solve?

  • Knowing the ecosystem landscape and being able to justify a choice for a given context shows experience beyond hobby projects.
22

What is React Query (TanStack Query) and why use it?

  • TanStack Query is a server-state management library — handles fetching, caching, synchronising, and updating data from APIs.
  • Features: background refetching, cache invalidation, pagination, optimistic updates, loading/error states, deduplication of concurrent requests.
  • useQuery for reads; useMutation for writes; QueryClient manages cache globally.
  • Key insight: Server state (async, shared, can become stale) is fundamentally different from client state (synchronous, local). Conflating them leads to complex, fragile code.

What problems does this solve?

  • React Query has become a de-facto standard for data fetching — showing familiarity with it is expected in modern React interviews.
23

How does React Router work?

  • React Router v6 provides client-side routing via BrowserRouter, <Routes>, <Route path='...' element={'{...}'}>.
  • Hooks: useNavigate (programmatic navigation), useParams (URL params), useSearchParams (query strings), useLocation.
  • Nested routes: Outlet renders the child route's component in a parent layout.
  • Loaders & Actions (v6.4+): Co-locate data fetching and mutations with routes — similar to Next.js route conventions.

What problems does this solve?

  • React Router is the standard routing solution for SPAs — understanding its v6 changes and hooks is expected.
24

What is forwardRef and when do you need it?

  • By default, the ref prop is not passed through to a child component. React.forwardRef lets a component expose its internal DOM node (or another ref value) to its parent.
  • Use cases: Building reusable input, button, or dialog components that need to be focusable/scrollable from a parent.

What problems does this solve?

  • forwardRef is essential when building a component library — any reusable input or focusable component will need it.
25

What is useImperativeHandle?

  • useImperativeHandle(ref, () => ({'{...}'}), deps) customises the value exposed to the parent via a ref — used with forwardRef.
  • Instead of exposing the raw DOM node, you can expose specific methods (e.g., focus, scrollTo, reset) while keeping other internals private.

What problems does this solve?

  • useImperativeHandle is the final escape hatch for imperative APIs — knowing it shows you understand the full ref system.
26

What does React.StrictMode do?

  • StrictMode is a development-only wrapper that highlights potential problems in an app.
  • In React 18, it:
    • Double-invokes component functions, reducers, and effects (mount → unmount → remount) to surface missing cleanups.
    • Detects deprecated API usage.
    • Warns about impure render functions with side effects.
  • Has no effect in production.
  • The double-mounting behaviour often surprises developers who see API calls fire twice — this is expected and expected to have proper cleanup.

What problems does this solve?

  • StrictMode surprises many developers — understanding why effects fire twice in development prevents wasted debugging time.
27

What are key React performance optimisation patterns?

  • Code splitting: React.lazy + dynamic imports to reduce initial bundle.
  • Memoisation: React.memo, useMemo, useCallback — but only when profiling shows it's needed.
  • Virtualisation: Render only visible items in long lists (react-virtual, react-window).
  • State colocation: Keep state as close to where it's used as possible — avoid lifting state too high.
  • Avoid anonymous functions in JSX: They create new references on each render (though React compiler may handle this in the future).
  • Transition API (React 18): startTransition marks non-urgent updates — keeps UI responsive during expensive renders.
  • Always use the React DevTools Profiler to identify actual bottlenecks before optimising.

What problems does this solve?

  • Performance optimisation is a senior-level topic — showing you reach for the profiler before applying fixes demonstrates engineering maturity.
28

How do you test React components?

  • React Testing Library (RTL): Query the DOM as a user would (by role, label, text). Preferred approach — tests implementation-agnostic behaviour.
  • Vitest / Jest: Test runner. RTL uses @testing-library/jest-dom for custom assertions.
  • User Interactions: Use @testing-library/user-event for realistic event simulation over fireEvent.
  • Mocking: vi.mock / jest.mock for modules; msw (Mock Service Worker) for API calls.
  • E2E: Playwright or Cypress for full integration tests against a running app.
  • Testing philosophy: test behaviour, not implementation details.

What problems does this solve?

  • Testing strategy is a senior signal — knowing RTL's philosophy and when to mock vs test real implementations shows production experience.
29

What are the core concepts of Next.js?

  • Next.js is the most popular React meta-framework — provides file-based routing, SSR, SSG, ISR, and React Server Components.
  • App Router (Next.js 13+): Directory-based routing using app/. All components are Server Components by default. "use client" opts into client components.
  • Rendering modes: SSR (per request), SSG (at build), ISR (regenerates on a schedule or on-demand), client-side.
  • Special files: layout.tsx, page.tsx, loading.tsx, error.tsx, not-found.tsx, route.ts (API routes).
  • Data fetching: fetch with cache/revalidate options in Server Components; generateStaticParams for static routes.

What problems does this solve?

  • Next.js is the standard production React framework — understanding its rendering model is expected in most frontend interviews today.
30

What is the difference between Class and Function Components?

  • Class components: Extend React.Component. Lifecycle via methods (componentDidMount, etc.). State via this.state. Verbose. Can be error boundaries.
  • Function components + Hooks: The modern standard since React 16.8. Simpler, composable, easier to test. Hooks replace all lifecycle methods.
  • When you still see class components: Error boundaries (no hook equivalent yet), legacy codebases.
  • The React team has stated there are no plans to remove class components, but all new APIs target function components.

What problems does this solve?

  • A fast, confident answer here shows historical context — important for working on any existing React codebase.