# 100 Most‑Asked React Interview Questions

How to use this file: skim the one‑liners to refresh, expand the answers for details, and practice with the follow‑ups. Code examples are minimal and runnable.


# Foundations & Core Concepts

# 1) What is React?

One‑liner: A UI library for building component‑based views using declarative rendering and state. Analogy: React is like a Lego set — components (bricks) snap together to build complex UIs. Follow‑ups: Why “library” not “framework”? What does “declarative” mean in practice?


# 2) JSX — what and why?

One‑liner: JSX is a syntax sugar that compiles to React.createElement(...) calls. Example:

const el = <h1>Hello</h1>; // becomes React.createElement('h1', null, 'Hello')
1

Analogy: JSX is like a templating dialect embedded in JS — closer to “HTML in JS,” not “templates plus JS.” Follow‑ups: Can React work without JSX? Pros/cons of JSX?


# 3) Virtual DOM and reconciliation

One‑liner: React diffs virtual trees and applies the minimal real DOM updates. Analogy: Compare “before vs after” blueprints, then only renovate the changed rooms. Follow‑ups: When is VDOM not a performance silver bullet?


# 4) Elements, nodes, and components — difference?

Difference table:

Term What it is Example
Node Anything React can render (string, number, element, null) "OK"
Element Immutable description of UI {type:'div', props:{}}
Component Function/class returning elements function App(){...}

Follow‑ups: When does React convert elements to nodes?


# 5) Props vs State

Difference table:

Props State
Ownership Parent‑controlled Component‑owned
Mutability Read‑only Mutable (via setters)
Usage Configure components Track UI/data changes

Example:

function Hello({name}) {
  const [count, setCount] = React.useState(0);
  return <button onClick={()=>setCount(c=>c+1)}>{name} {count}</button>;
}
1
2
3
4

Follow‑ups: When would you lift state vs keep local?


# 6) Controlled vs Uncontrolled components

Difference table:

Controlled Uncontrolled
Source of truth React state DOM (refs)
Validation Easier Manual
Performance May re-render often Fewer renders

Example (controlled):

const [v,setV] = React.useState("");
<input value={v} onChange={e=>setV(e.target.value)} />
1
2

Follow‑ups: When are uncontrolled inputs handy? (e.g., large forms, simple one‑offs)


# 7) Keys in lists — why unique?

One‑liner: Stable keys help React reconcile list items efficiently and correctly. Anti‑pattern: Using array index as key when list order can change. Follow‑ups: When is index key acceptable?


# 8) Conditional rendering patterns

Example:

{isLoading ? <Spinner/> : items.length ? <List items={items}/> : <Empty/>}
1

Patterns: ternary, guard return, logical &&, render functions. Follow‑ups: Tradeoffs among patterns?


# 9) Composition vs Inheritance

One‑liner: Prefer composing components and props (children, render props) over class inheritance. Example:

<Card><UserAvatar/></Card>
1

Follow‑ups: When would you use composition to avoid prop drilling?


# 10) Lifting state up

One‑liner: Move shared state to a common ancestor to synchronize siblings. Example:

function Parent(){
  const [val,setVal]=React.useState(0);
  return (<><A val={val}/><B onInc={()=>setVal(v=>v+1)}/></>);
}
1
2
3
4

Follow‑ups: When does lifting become global state?


# Hooks

# 11) What is a Hook?

One‑liner: A function that lets function components “hook into” React features (state, effects, refs). Follow‑ups: Why only call hooks at top level?


# 12) Rules of Hooks

One‑liner: Call hooks at top level and only in React functions (not loops/conditions/regular JS). Why: Ensures hook ordering is consistent between renders.


# 13) useState — setter forms

One‑liner: Pass a value or an updater function to avoid stale reads.

const [c,setC]=useState(0);
setC(c+1);       // may be stale in batches
setC(prev=>prev+1); // safe
1
2
3

Follow‑ups: Why are state updates batched?


# 14) useEffect — dependencies and cleanup

One‑liner: Run side effects after render; specify dependencies to control when.

useEffect(()=>{
  const id = setInterval(()=>setTick(t=>t+1), 1000);
  return ()=>clearInterval(id); // cleanup
}, []);
1
2
3
4

Follow‑ups: How to avoid stale closures?


# 15) useMemo vs useCallback

Difference:

  • useMemo(fn, deps) caches a computed value.
  • useCallback(fn, deps) caches a function reference. Follow‑ups: When to avoid premature memoization?

# 16) useRef — two common uses

One‑liner: Hold mutable value across renders; access DOM nodes.

const countRef = React.useRef(0); // mutable box
const inputRef = React.useRef();  // DOM ref
1
2

Follow‑ups: Why no re-render on ref changes?


# 17) Custom hooks — extracting logic

One‑liner: Package reusable stateful logic.

function useOnline(){
  const [online,setOnline]=useState(navigator.onLine);
  useEffect(()=>{
    const on=()=>setOnline(true), off=()=>setOnline(false);
    window.addEventListener('online',on); window.addEventListener('offline',off);
    return ()=>{window.removeEventListener('online',on);window.removeEventListener('offline',off)};
  },[]);
  return online;
}
1
2
3
4
5
6
7
8
9

Follow‑ups: How to test custom hooks?


# 18) useLayoutEffect vs useEffect

Difference: useLayoutEffect runs synchronously after DOM mutations (paint is blocked); useEffect runs after paint. Follow‑ups: When to prefer layout effect? (measure DOM, avoid flicker)


# 19) useReducer vs useState

Difference: useReducer centralizes updates for complex transitions; useState keeps state local and simple.

function reducer(s,a){ switch(a.type){ case 'inc': return s+1; default: return s;} }
const [state,dispatch] = useReducer(reducer,0);
1
2

Follow‑ups: When to co-locate vs globalize state?


# 20) useImperativeHandle & forwardRef

One‑liner: Limit what parent can do imperatively with child refs.

const Fancy = React.forwardRef((props,ref)=>{
  const inputRef = useRef();
  useImperativeHandle(ref, ()=>({ focus: ()=> inputRef.current?.focus() }));
  return <input ref={inputRef}/>;
});
1
2
3
4
5

Follow‑ups: Why keep imperative APIs minimal?


# Rendering & Performance

# 21) Re-render triggers

One‑liner: Props/state changes, context updates, and parent re-renders. Follow‑ups: How to profile re-renders?


# 22) React.memo — when and how

One‑liner: Memoize function components to skip render if props are shallow‑equal.

const Row = React.memo(function Row({item}){return <li>{item.name}</li>});
1

Follow‑ups: Why over‑memoization can hurt?


# 23) useMemo pitfalls

One‑liner: If recompute is cheap or deps change often, memo won’t help. Follow‑ups: How to prove it with Profiler?


# 24) Keyed lists vs index keys

One‑liner: Index keys break identity on reorder/delete; prefer stable IDs. Follow‑ups: When lists are truly static?


# 25) Avoiding prop‑drilling

Options: Context, composition, co‑locating state, event bubbling, or global store. Follow‑ups: When does Context become overused?


# 26) Suspense — what does it do?

One‑liner: Lets components wait for async data by showing fallback UI. Follow‑ups: Relationship with concurrent rendering?


# 27) Concurrent rendering (concept)

Analogy: Like having draft renders that React may discard if newer updates arrive (“time slicing”). Follow‑ups: Does it guarantee faster apps?


# 28) Error boundaries

One‑liner: Catch render errors in subtree and render fallback (class only for now).

class Boundary extends React.Component{
  state={err:null};
  static getDerivedStateFromError(e){return {err:e};}
  componentDidCatch(e,info){/* log */}
  render(){return this.state.err? <h1>Oops</h1> : this.props.children;}
}
1
2
3
4
5
6

Follow‑ups: What errors are not caught? (event handlers, async, etc.)


# 29) Portals

One‑liner: Render children into a different DOM subtree.

return ReactDOM.createPortal(<Modal/>, document.getElementById('modal-root'));
1

Follow‑ups: Accessibility considerations?


# 30) StrictMode

One‑liner: Dev‑only checks: highlight unsafe lifecycles, double‑invoke certain functions to surface issues. Follow‑ups: Why are some effects run twice in dev?


# Routing

# 31) Client‑side routing basics

One‑liner: Intercepts navigation and updates UI without full page reloads. Follow‑ups: SEO tradeoffs and mitigations?


# 32) Route params & search params

import {useParams, useSearchParams} from 'react-router-dom';
1

Follow‑ups: How to handle optional params?


# 33) Code‑splitting routes

const Page = React.lazy(()=>import('./Page'));
<Suspense fallback={<Spinner/>}><Page/></Suspense>
1
2

Follow‑ups: Error boundary needs?


# Forms & Validation

# 34) Debounced inputs

const [value,setValue]=useState("");
useEffect(()=>{ const id=setTimeout(()=>onChange(value),300); return ()=>clearTimeout(id) },[value]);
1
2

Follow‑ups: Why debounce at edges?


# 35) Derived state — avoid duplication

One‑liner: Derive view from source state instead of storing duplicated state. Follow‑ups: Bad example of duplicated state?


# 36) Form libs vs hand‑rolled

Difference:

  • Libraries: Schema validation, nested fields, perf tricks.
  • Hand‑rolled: Total control, smaller bundle. Follow‑ups: When to switch?

# State Management

# 37) Local vs global vs server state

Difference: UI‑local (component), app‑wide (context/store), and remote cache (server state libs). Follow‑ups: Why treat server state differently?


# 38) Context — when and how

const ThemeContext = React.createContext('light');
function App(){ return <ThemeContext.Provider value="dark"><Page/></ThemeContext.Provider>}
1
2

Follow‑ups: Perf costs of context changes?


# 39) Redux vs Context

Difference: Redux = predictable centralized state + tooling; Context = dependency injection mechanism. Follow‑ups: When Redux Toolkit over classic Redux?


# 40) Server state tools (e.g., React Query)

One‑liner: Treat remote data as a cache: fetching, caching, invalidation, background sync. Follow‑ups: Cache invalidation strategies?


# Data Fetching Patterns

# 41) Fetch in effects (classic)

useEffect(()=>{ let alive = true;
  fetch(url).then(r=>r.json()).then(data=>{ if(alive) setData(data); });
  return ()=>{alive=false};
}, [url]);
1
2
3
4

Follow‑ups: AbortController vs flag pattern?


# 42) Suspense for data fetching (concept)

One‑liner: Components let React wait; hooks throw promises to signal pending data. Follow‑ups: What is a resource wrapper pattern?


# 43) Error handling UI

One‑liner: Show fallback, retry, toast; separate transport errors from domain errors. Follow‑ups: Retrying strategies?


# Testing

# 44) RTL vs Enzyme

Difference: RTL tests behavior from user’s perspective; Enzyme (legacy) focused on internals. Follow‑ups: Why prefer RTL with JSDOM?


# 45) Unit test a hook

// with @testing-library/react
function Counter(){const [c,setC]=useState(0); return <button onClick={()=>setC(c+1)}>{c}</button>}
1
2

Follow‑ups: What to assert for effects?


# 46) Snapshot tests — pros/cons

Pros: Quick regression checks. Cons: Brittle, noisy diffs. Follow‑ups: When are they valuable?


# Build, Tooling, Ecosystem

# 47) CRA, Vite, Next.js — differences

Difference:

  • CRA: Legacy scaffolding; heavier.
  • Vite: Fast dev server, modern build.
  • Next.js: Framework with routing, SSR/SSG, edge. Follow‑ups: When pick each?

# 48) Tree‑shaking & dead‑code elimination

One‑liner: Use ES modules and avoid side‑effects to enable eliminations. Follow‑ups: Why mark sideEffects: false?


# 49) Bundle splitting and dynamic import

const Widget = React.lazy(()=>import('./Widget'));
1

Follow‑ups: Granularity trade‑offs?


# 50) Source maps and debugging

One‑liner: Map transpiled code back to source for better debugging. Follow‑ups: Security concerns in prod?


# Accessibility & UX

# 51) ARIA basics in React

One‑liner: Use semantic HTML first; add ARIA when needed; tie labels via htmlFor/id. Follow‑ups: Managing focus after modal open?


# 52) Keyboard navigation

One‑liner: Tab order, roving tabindex, aria-activedescendant, focus traps. Follow‑ups: How to test with RTL?


# 53) Announcing async updates

const liveRef = useRef();
useEffect(()=>{ liveRef.current.textContent = `Loaded ${count} items`; },[count]);
<span role="status" aria-live="polite" ref={liveRef} />
1
2
3

Follow‑ups: aria-busy usage?


# Advanced Patterns

# 54) Render props

<DataProvider render={(data)=> <List data={data}/> }/>
1

Follow‑ups: Compare to custom hooks?


# 55) Higher‑Order Components (HOCs)

One‑liner: Functions that take a component and return an enhanced one. Follow‑ups: Pitfalls (wrapping hell, refs, displayName).


# 56) Controlled compound components

One‑liner: Parent orchestrates state for a set of subcomponents (e.g., Tabs). Follow‑ups: Context + state machine approach?


# 57) State machines with React

One‑liner: Explicit states and transitions reduce edge‑case bugs. Follow‑ups: Where do machines shine (wizards, async, forms)?


# 58) Headless UI components

One‑liner: Logic without styling; consumers bring their own UI. Follow‑ups: Pros/cons for design systems.


# 59) React performance checklist (quick)

Points: keys, memoization, split bundles, avoid unnecessary context churn, measure first. Follow‑ups: How to detect wasted renders?


# 60) Lazy images & IntersectionObserver

const ref=useRef();
useEffect(()=>{ const io = new IntersectionObserver(([e])=>{ if(e.isIntersecting) load(); }); io.observe(ref.current); return ()=>io.disconnect(); },[]);
1
2

Follow‑ups: Polyfills/server rendering caveats?


# Next.js / SSR / SSG (framework concepts that often appear)

# 61) SSR vs SSG vs CSR

Difference:

  • SSR: Render on server per request.
  • SSG: Pre‑render at build time.
  • CSR: Render in browser. Follow‑ups: SEO and TTFB trade‑offs?

# 62) Next.js data fetching styles (concept)

One‑liner: Route handlers, server actions, fetch with caching, edge runtime. Follow‑ups: Revalidation strategies?


# 63) Image optimization

One‑liner: Responsive sizes, lazy loading, modern formats. Follow‑ups: When not to optimize?


# Type Safety

# 64) Typing props with TS

type Props={title:string; onClick?:()=>void};
function Button({title,onClick}:Props){ return <button onClick={onClick}>{title}</button> }
1
2

Follow‑ups: Pros/cons of React.FC?


# 65) Typing events

function Input(){ const onChange=(e:React.ChangeEvent<HTMLInputElement>)=>{}; }
1

Follow‑ups: Synthetic vs native events?


# 66) Generic components

function List<T>({items, render}:{items:T[]; render:(t:T)=>React.ReactNode}){
  return <ul>{items.map(render)}</ul>;
}
1
2
3

Follow‑ups: Inference tricks?


# Edge Cases & Gotchas

# 67) Stale closures in effects

One‑liner: Effect uses values from render it was defined in; include deps or use refs. Follow‑ups: Why exhaustive‑deps rule exists?


# 68) Derived state from props (anti‑pattern)

One‑liner: Prefer memoized derived values; if you must mirror, keep one source of truth. Follow‑ups: getDerivedStateFromProps pitfalls?


# 69) setState batching

One‑liner: Multiple updates may be batched; use updater form to avoid races. Follow‑ups: Microtasks vs macrotasks relevance?


# 70) Keys and component state loss

One‑liner: Changing key remounts component (state resets). Follow‑ups: Useful for resetting forms?


# Styling

# 71) CSS Modules vs CSS‑in‑JS vs Tailwind

Difference:

  • Modules: Scoped classnames, build‑time.
  • CSS‑in‑JS: Runtime/theming/dynamic styles.
  • Utility CSS: Tokenized classes, fast iteration. Follow‑ups: Bundle and runtime impacts?

# 72) Inline styles caveats

One‑liner: No pseudo‑classes/media queries; objects re‑create on each render unless memoized. Follow‑ups: Style object memoization?


# 73) Theming approaches

One‑liner: Context tokens, CSS variables, or CSS‑in‑JS theme objects. Follow‑ups: Dark mode strategies?


# Component Design & APIs

# 74) Prop naming and ergonomics

One‑liner: Prefer single source of truth, avoid conflicting props, provide sensible defaults. Follow‑ups: When to expose render props vs children?


# 75) Controlled vs uncontrolled APIs (component API design)

One‑liner: Offer both when possible; document precedence rules. Follow‑ups: How to design priority between props and internal state?


# 76) Accessibility of custom widgets

One‑liner: Manage focus, roles, keyboard interactions; announce changes. Follow‑ups: Reference WAI‑ARIA Authoring Practices?


# Real‑World Scenarios

# 77) Infinite scrolling list

One‑liner: Virtualize rows, observer for sentinel, cache pages. Follow‑ups: Windowing libs (react‑window, react‑virtual)?


# 78) File uploads

One‑liner: Controlled inputs + progress + cancel via AbortController. Follow‑ups: Chunked uploads and retries?


# 79) Web sockets with React

One‑liner: Manage socket outside render, expose via context or custom hook. Follow‑ups: Cleanup and reconnection?


# 80) Optimistic UI

One‑liner: Pretend success, rollback on failure, keep mutation IDs. Follow‑ups: Idempotent server APIs?


# Architecture & Patterns

# 81) Feature folders vs monolith components

One‑liner: Group by feature/domain; keep components small and cohesive. Follow‑ups: Module boundaries and ownership?


# 82) Error handling strategy

One‑liner: Boundary + toast + retry; centralize logging. Follow‑ups: User‑recoverable vs developer errors?


# 83) Internationalization (i18n)

One‑liner: Message catalogs, ICU formats, RTL support, locale‑aware formatting. Follow‑ups: Lazy‑loading locale bundles?


# 84) Forms with async validation

One‑liner: Validate on blur/submit; debounce server checks. Follow‑ups: Race conditions and last‑write‑wins?


# 85) Data normalization

One‑liner: Store entities by id; derive denormalized views. Follow‑ups: Normalization helpers (normalizr)?


# 86) Deeply nested updates

One‑liner: Immer or reducers; avoid prop drilling via context. Follow‑ups: Structural sharing for performance?


# 87) Feature flags

One‑liner: Gate UI by flags; evaluate server/client with hydration awareness. Follow‑ups: Kill‑switch strategies?


# 88) Logging and analytics

One‑liner: Log meaningful events, respect privacy, throttle. Follow‑ups: Where to place trackers in React tree?


# Miscellaneous

# 89) Fragments vs div wrappers

One‑liner: Avoid extra nodes; use <>...</> or React.Fragment. Follow‑ups: Keyed fragments?


# 90) PropTypes vs TypeScript

Difference: PropTypes = runtime checks; TS = compile‑time checks. Follow‑ups: Can both coexist?


# 91) PureComponent vs memo

Difference: Class optimization vs function counterpart with shallow compare. Follow‑ups: Custom comparison function in memo?


# 92) Event pooling (historical)

One‑liner: Synthetic events used to be pooled; now generally not — but don’t async‑hold references blindly. Follow‑ups: Access e.persist() history?


# 93) Refs vs state for triggering re-render

One‑liner: Changing refs doesn’t re-render; use state for UI changes. Follow‑ups: When to keep counters in refs?


# 94) Hydration (SSR)

One‑liner: Attach event listeners to server‑rendered markup; mismatches cause warnings. Follow‑ups: Avoiding hydration mismatches?


# 95) Windowing / virtualization

One‑liner: Render visible slice to keep DOM light. Follow‑ups: Overscan tuning?


# 96) Data persistence (localStorage)

useEffect(()=>{ localStorage.setItem('count', String(count)); },[count]);
1

Follow‑ups: Serialization and quota errors?


# 97) Dependency arrays — how to think

Analogy: Think of an effect as subscribing to the values in the deps list. Follow‑ups: Why linters enforce exhaustive deps?


# 98) Race conditions in async effects

One‑liner: Track request ids/AbortController; set state only for latest. Follow‑ups: Show an example with out‑of‑order responses.


# 99) Reusable list renderers

function List({items, render}){ return <ul>{items.map(render)}</ul> }
1

Follow‑ups: Key placement and stability?


# 100) The “one source of truth” rule

One‑liner: Keep canonical data in one place; derive everything else. Follow‑ups: Show a bug caused by duplicating state.


# Bonus: Quick Practice Prompts (Not counted)

  • Refactor a class component with lifecycles into hooks.
  • Build a debounced search box with async fetch and empty‑state UX.
  • Create a tab system with keyboard navigation and ARIA roles.
  • Add Suspense boundaries and error boundary around a lazy route.
  • Implement optimistic mutation with rollback using a server‑state library.

# Final Tip

Measure first, optimize second. Use React DevTools Profiler to validate every “optimization” claim.