React JS Interviw Question: The codeing challenge and machine round

100 Comprehensive React JS Interview Questions & Answers. Master everything from Beginner hooks to Expert-level React JS coding challenge and machine round interview.

Beginner Level

Q01
What is React? What are its core features?
Beginner

React is an open-source JavaScript library created by Facebook for building user interfaces, particularly single-page applications. Its core features are:

  • Component-based architecture — UI is split into reusable, self-contained pieces.
  • Virtual DOM — React keeps a lightweight in-memory copy of the real DOM and only updates what changed, boosting performance.
  • JSX — A syntax extension that lets you write HTML-like code inside JavaScript.
  • Unidirectional data flow — Data flows from parent to child via props, making apps easier to debug.
  • Hooks — Functions like useState and useEffect that add state and lifecycle behavior to functional components.
Q02
What is JSX and why do we use it?
Beginner

JSX (JavaScript XML) is a syntax extension that allows you to write HTML-like markup inside JavaScript files. It is not valid JavaScript — Babel transpiles it into React.createElement() calls at build time.

// JSX
const element = <h1 className="title">Hello, World!</h1>;

// What Babel compiles it to
const element = React.createElement('h1', { className: 'title' }, 'Hello, World!');

JSX makes component code more readable and easier to reason about compared to chained createElement calls.

Q03
What is the difference between a class component and a functional component?
Beginner
// Class Component
class Greeting extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

// Functional Component (preferred)
function Greeting({ name }) {
  return <h1>Hello, {name}</h1>;
}

Functional components are simpler, use less boilerplate, and since React 16.8 can use Hooks for state and side-effects. Class components require this, lifecycle methods, and are generally more verbose. New code should prefer functional components.

Q04
What are props in React? How do you pass them?
Beginner

Props (short for properties) are read-only inputs passed from a parent component to a child component. They make components reusable by letting the parent control child behavior/appearance.

function Button({ label, color }) {
  return <button style={{ background: color }}>{label}</button>;
}

// Usage
<Button label="Submit" color="blue" />

Props are immutable inside the child — the child must never modify them directly.

Q05
What is state in React and how is it different from props?
Beginner

State is mutable data managed inside a component. When state changes, the component re-renders. Props are immutable data passed from outside.

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

Think of props as arguments to a function and state as local variables that persist across renders.

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

The Virtual DOM is a lightweight JavaScript object tree that mirrors the real DOM. When state or props change, React:

  • Renders a new Virtual DOM tree.
  • Diffs it against the previous tree (reconciliation).
  • Computes the minimal set of real DOM mutations.
  • Applies only those changes to the actual browser DOM.

This batched, minimal-update strategy is far faster than naive full-page re-renders.

Q07
How does useState work? Give an example.
Beginner

useState is a Hook that adds local state to a functional component. It returns a tuple: the current value and a setter function.

import { useState } from 'react';

function Toggle() {
  const [isOn, setIsOn] = useState(false);

  return (
    <button onClick={() => setIsOn(prev => !prev)}>
      {isOn ? 'ON' : 'OFF'}
    </button>
  );
}

The functional updater form prev => !prev is preferred when the new value depends on the old one, because React may batch state updates.

Q08
What is useEffect and when do you use it?
Beginner

useEffect lets you perform side-effects (data fetching, subscriptions, DOM mutations, timers) after render. It runs after the component renders and optionally cleans up before re-running.

import { useState, useEffect } from 'react';

function UserCard({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetch(`/api/users/${userId}`)
      .then(r => r.json())
      .then(setUser);

    // cleanup (runs before next effect or unmount)
    return () => setUser(null);
  }, [userId]); // re-runs only when userId changes

  if (!user) return <p>Loading...</p>;
  return <p>{user.name}</p>;
}
Q09
What are React Hooks? Name five built-in Hooks.
Beginner

Hooks are functions that let functional components tap into React features that were previously only available in class components.

  • useState — local component state
  • useEffect — side-effects and lifecycle
  • useContext — consume a React context
  • useRef — mutable ref object / DOM access
  • useMemo — memoize expensive computed values
  • useCallback — memoize callback functions
  • useReducer — complex state with reducer pattern

Rules of Hooks: only call at the top level, only call inside React functions — never inside conditionals or loops.

Q10
What is the purpose of the key prop in lists?
Beginner

The key prop helps React identify which items in a list have changed, been added, or removed during reconciliation. Keys must be stable, unique among siblings, and ideally come from your data (e.g., database IDs).

const items = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];

function List() {
  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>{item.name}</li> // ✅ stable, unique
      ))}
    </ul>
  );
}

Avoid using array index as key when the list can be reordered — this causes subtle re-render bugs.

Q11
What is conditional rendering in React?
Beginner

Conditional rendering lets you show or hide UI based on state or props. Common patterns:

function Alert({ isError, message }) {
  // if/else
  if (isError) return <div className="error">{message}</div>;

  // ternary
  return <div>{message ? message : 'No messages'}</div>;

  // short-circuit &&
  return <div>{message && <span>{message}</span>}</div>;
}
Q12
How do you handle events in React?
Beginner

React events use camelCase names and receive a SyntheticEvent — a cross-browser wrapper around the native event.

function Form() {
  function handleSubmit(e) {
    e.preventDefault(); // prevent page reload
    console.log('submitted');
  }

  return (
    <form onSubmit={handleSubmit}>
      <input onChange={e => console.log(e.target.value)} />
      <button type="submit">Send</button>
    </form>
  );
}
Q13
What is React.Fragment and why is it useful?
Beginner

Fragments let you group multiple elements without adding an extra DOM node. This avoids invalid HTML (e.g., a <tr> inside a <div>) and keeps the DOM clean.

// Short syntax
function Columns() {
  return (
    <>
      <td>Name</td>
      <td>Age</td>
    </>
  );
}

// With key (must use long form)
items.map(item => (
  <React.Fragment key={item.id}>
    <dt>{item.term}</dt>
    <dd>{item.def}</dd>
  </React.Fragment>
))
Q14
What is useRef? Give two use cases.
Beginner

useRef returns a mutable object { current: value } that persists across renders without causing re-renders when changed.

// Use case 1: access a DOM node
function FocusInput() {
  const inputRef = useRef(null);
  return (
    <>
      <input ref={inputRef} />
      <button onClick={() => inputRef.current.focus()}>Focus</button>
    </>
  );
}

// Use case 2: store a mutable value (e.g. previous state)
function Timer() {
  const timerIdRef = useRef(null);
  const start = () => { timerIdRef.current = setInterval(tick, 1000); };
  const stop  = () => clearInterval(timerIdRef.current);
  // ...
}
Q15
What is prop drilling and what problems does it cause?
Beginner

Prop drilling happens when you must pass data through many intermediate components just to reach a deeply nested consumer that actually needs it.

// theme has to travel A → B → C even though B doesn't use it
<A theme="dark" />
  <B theme={theme} />    // B just passes it down
    <C theme={theme} />  // C actually uses it

Problems: tight coupling, verbose code, hard to refactor. Solutions include React Context, Redux, Zustand, or component composition.

Q16
What is React Context and how do you use it?
Beginner

Context provides a way to share values (theme, auth, locale) across the component tree without prop drilling.

const ThemeContext = React.createContext('light');

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  const theme = useContext(ThemeContext);
  return <div className={theme}>Toolbar</div>;
}

Context should be used for low-frequency global data. For high-frequency updates, prefer a state manager to avoid unnecessary re-renders.

Q17
How do you lift state up in React?
Beginner

When two sibling components need to share state, you lift the state to their closest common ancestor and pass it down as props.

function Parent() {
  const [value, setValue] = useState('');
  return (
    <>
      <Input value={value} onChange={setValue} />
      <Display value={value} />
    </>
  );
}

function Input({ value, onChange }) {
  return <input value={value} onChange={e => onChange(e.target.value)} />;
}

function Display({ value }) {
  return <p>{value}</p>;
}
Q18
What are controlled vs uncontrolled components?
Beginner

A controlled component has its form input value driven by React state. A uncontrolled component manages its own state internally via the DOM; you read the value with a ref.

// Controlled
const [text, setText] = useState('');
<input value={text} onChange={e => setText(e.target.value)} />

// Uncontrolled
const inputRef = useRef();
<input ref={inputRef} defaultValue="hello" />
// read: inputRef.current.value

Controlled components give you full control over validation and transformations on every keystroke. Uncontrolled components are simpler for basic forms and integrating with non-React code.

Q19
What is React.StrictMode?
Beginner

StrictMode is a developer tool that helps you spot potential problems. It intentionally double-invokes render functions, state initializers, and effects (in development) to surface side-effects written incorrectly. It has no effect in production builds.

<React.StrictMode>
  <App />
</React.StrictMode>

Warnings it catches: deprecated API usage, impure render side-effects, unexpected re-render issues, and missing cleanup in effects.

Q20
How do you update an object or array in state correctly?
Beginner

State must be treated as immutable. Always return a new object/array instead of mutating the existing one.

// ❌ Wrong — mutates directly
state.user.name = 'Alice'; setState(state);

// ✅ Correct — spread into new object
setState(prev => ({ ...prev, user: { ...prev.user, name: 'Alice' } }));

// ✅ Array: add item
setItems(prev => [...prev, newItem]);

// ✅ Array: remove item
setItems(prev => prev.filter(item => item.id !== targetId));

// ✅ Array: update item
setItems(prev => prev.map(item => item.id === targetId ? { ...item, done: true } : item));
Q21
What is the difference between null and undefined rendering in JSX?
Beginner

Both null, undefined, and false render nothing — they are valid children that produce no DOM output. This makes them ideal for conditional rendering.

function Component({ show }) {
  return (
    <div>
      {show && <p>Visible!</p>}  // nothing rendered when show=false
      {null}                            // nothing rendered
      {0}                               // ⚠️ renders "0"! be careful
    </div>
  );
}

Note: the number 0 does render — a common footgun when using count && <Comp />.

Q22
What is default props and how do you set it?
Beginner
// Modern: destructuring defaults
function Button({ label = 'Click me', color = 'blue' }) {
  return <button style={{ color }}>{label}</button>;
}

// Legacy: static property
Button.defaultProps = { label: 'Click me', color: 'blue' };

Destructuring defaults are preferred in modern React since defaultProps may be removed in a future major version.

Q23
What is children prop and how is it used?
Beginner

The children prop contains everything placed between the component’s opening and closing tags, enabling composable wrapper components.

function Card({ children, title }) {
  return (
    <div className="card">
      <h2>{title}</h2>
      {children}
    </div>
  );
}

// Usage
<Card title="Hello">
  <p>I am a child!</p>
</Card>
Q24
How do you apply inline styles in React?
Beginner

In React, the style attribute accepts a JavaScript object with camelCased property names and string values (not a CSS string).

const styles = {
  backgroundColor: '#0d1117',
  fontSize: '16px',
  marginTop: 8,          // numbers default to px
  fontWeight: 'bold',
};

<div style={styles}>Styled</div>
// or inline:
<div style={{ color: 'red' }}>Red</div>
Q25
What happens when you call setState multiple times in a row?
Beginner

React batches multiple state updates in event handlers (and in React 18+, everywhere including async code) into a single re-render for performance.

function Component() {
  const [a, setA] = useState(0);
  const [b, setB] = useState(0);

  function handleClick() {
    setA(1); // batched
    setB(2); // batched
    // → only ONE re-render occurs
  }
}

If you need the current state value based on the previous update, use the functional updater form: setCount(prev => prev + 1).

Intermediate Level

Q26
What is useReducer and when should you use it over useState?
Intermediate

useReducer is ideal when state transitions depend on the previous state and multiple sub-values change together, or when the next state logic is complex.

const initialState = { count: 0, step: 1 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment': return { ...state, count: state.count + state.step };
    case 'setStep':   return { ...state, step: action.payload };
    default: throw new Error('Unknown action');
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      <p>{state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
    </>
  );
}
Q27
What is useMemo and when should you use it?
Intermediate

useMemo memoizes the result of an expensive computation, recomputing it only when dependencies change. It prevents unnecessary recalculations on every render.

import { useMemo } from 'react';

function ProductList({ products, filter }) {
  const filtered = useMemo(
    () => products.filter(p => p.category === filter),
    [products, filter]  // only recompute when these change
  );

  return filtered.map(p => <ProductCard key={p.id} product={p} />);
}

Don’t over-optimize — only use useMemo when a profiler shows a real bottleneck. The memoization itself has overhead.

Q28
What is useCallback and how does it differ from useMemo?
Intermediate

useCallback(fn, deps) memoizes a function reference. It’s equivalent to useMemo(() => fn, deps). Use it when passing callbacks to memoized child components to prevent unnecessary re-renders.

const handleClick = useCallback(() => {
  doSomethingWith(id);
}, [id]); // stable reference unless id changes

// useMemo — memoizes a VALUE
const total = useMemo(() => items.reduce((s, i) => s + i.price, 0), [items]);

// useCallback — memoizes a FUNCTION
const getTotal = useCallback(() => items.reduce((s, i) => s + i.price, 0), [items]);
Q29
What is React.memo? How does it work?
Intermediate

React.memo is a higher-order component that memoizes a functional component. It skips re-rendering if props haven’t changed (shallow comparison).

const ExpensiveChild = React.memo(function({ value }) {
  console.log('rendered');
  return <div>{value}</div>;
});

// Custom comparator
const MemoComp = React.memo(Comp, (prev, next) => {
  return prev.id === next.id; // return true → skip re-render
});

Works best when paired with useCallback/useMemo for stable prop references.

Q30
What is a custom Hook? Write one that fetches data.
Intermediate

A custom Hook is a function whose name starts with use and that calls other Hooks. It extracts reusable stateful logic from components.

function useFetch(url) {
  const [data, setData]   = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    let cancelled = false;
    setLoading(true);
    fetch(url)
      .then(r => r.json())
      .then(d => { if (!cancelled) setData(d); })
      .catch(e => { if (!cancelled) setError(e); })
      .finally(() => { if (!cancelled) setLoading(false); });
    return () => { cancelled = true; };
  }, [url]);

  return { data, loading, error };
}

// Usage
const { data, loading } = useFetch('/api/users');
Q31
What is reconciliation in React?
Intermediate

Reconciliation is the algorithm React uses to diff the new Virtual DOM tree against the previous one and determine the minimal set of real DOM changes needed.

Key heuristics:

  • Elements of different types produce entirely different trees (full subtree rebuild).
  • The developer can hint stable identity with the key prop.
  • Same type → React updates props in place, keeping DOM node and children.

React 18 uses the Fiber architecture which makes reconciliation interruptible, enabling concurrent features like Suspense and transitions.

Q32
What is React Fiber?
Intermediate

Fiber is React’s internal reconciliation engine (introduced in React 16). It reimplements the reconciler using a linked list of “fiber” units of work, allowing React to pause, resume, abort, and prioritize rendering work.

This enables:

  • Concurrent rendering — interruptible renders that keep the UI responsive.
  • Suspense & lazy loading — pause rendering until async data or components are ready.
  • startTransition — mark non-urgent state updates so urgent updates (typing) stay fast.
Q33
What is React.lazy and Suspense? Write an example.
Intermediate

React.lazy lets you code-split a component into a separate bundle loaded on demand. Suspense shows a fallback while it loads.

import { lazy, Suspense } from 'react';

const Dashboard = lazy(() => import('./Dashboard'));

function App() {
  return (
    <Suspense fallback={<Spinner />}>
      <Dashboard />
    </Suspense>
  );
}

The browser only downloads the Dashboard bundle when it’s first rendered. Useful for route-level code splitting.

Q34
What are Error Boundaries? How do you create one?
Intermediate

Error Boundaries are class components that catch JavaScript errors in their child tree and display a fallback UI instead of crashing the whole app. They must implement static getDerivedStateFromError or componentDidCatch.

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError() {
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    logErrorToService(error, info.componentStack);
  }

  render() {
    if (this.state.hasError)
      return <h2>Something went wrong.</h2>;
    return this.props.children;
  }
}

Note: Error boundaries don’t catch errors in event handlers or async code — use regular try/catch for those.

Q35
What is the useLayoutEffect Hook? How is it different from useEffect?
Intermediate

useLayoutEffect fires synchronously after all DOM mutations but before the browser paints. useEffect fires after the paint.

useLayoutEffect(() => {
  // Measure DOM, synchronously update layout
  const rect = ref.current.getBoundingClientRect();
  setWidth(rect.width);
}); // no flicker — runs before browser paint

Use useLayoutEffect when you need to read layout from the DOM and synchronously re-render to prevent visual flicker (e.g., tooltips, measuring elements). For everything else, prefer useEffect to avoid blocking the paint.

Q36
What is the React Portals API and when would you use it?
Intermediate

Portals render children into a DOM node that exists outside the parent component’s DOM hierarchy, while still keeping them in the React component tree (events bubble normally).

import { createPortal } from 'react-dom';

function Modal({ children }) {
  return createPortal(
    <div className="modal">{children}</div>,
    document.getElementById('modal-root')  // DOM outside app root
  );
}

Common use cases: modals, tooltips, dropdowns — anything that needs to visually escape overflow-hidden or z-index constraints of its parent.

Q37
What is forwardRef and why is it needed?
Intermediate

By default, ref cannot be passed as a prop to a functional component. forwardRef lets you expose a ref from a parent to a DOM node inside the child.

const Input = React.forwardRef((props, ref) => (
  <input ref={ref} {...props} />
));

function Parent() {
  const inputRef = useRef();
  return <Input ref={inputRef} />; // ref reaches the <input> DOM node
}

Commonly used in design system libraries to give consumers direct DOM access while keeping internal implementation details abstracted.

Q38
What is the difference between useEffect with no deps, empty array [], and dependencies?
Intermediate
// No dependency array → runs after EVERY render
useEffect(() => { console.log('every render'); });

// Empty array [] → runs ONCE after mount
useEffect(() => { console.log('mounted'); }, []);

// With deps → runs on mount AND when any dep changes
useEffect(() => {
  console.log('userId changed');
}, [userId]);

The cleanup function returned from useEffect runs before the next effect execution or on unmount — in all three cases.

Q39
How does React handle forms? Build a simple validated form.
Intermediate
function LoginForm() {
  const [fields, setFields] = useState({ email: '', password: '' });
  const [errors, setErrors] = useState({});

  function validate() {
    const e = {};
    if (!fields.email.includes('@')) e.email = 'Invalid email';
    if (fields.password.length < 8) e.password = 'Min 8 chars';
    return e;
  }

  function handleSubmit(e) {
    e.preventDefault();
    const e2 = validate();
    if (Object.keys(e2).length) { setErrors(e2); return; }
    submitToServer(fields);
  }

  const change = field => e =>
    setFields(prev => ({ ...prev, [field]: e.target.value }));

  return (
    <form onSubmit={handleSubmit}>
      <input value={fields.email} onChange={change('email')} />
      {errors.email && <span>{errors.email}</span>}
      <input type="password" value={fields.password} onChange={change('password')} />
      {errors.password && <span>{errors.password}</span>}
      <button type="submit">Login</button>
    </form>
  );
}
Q40
What is the Render Props pattern?
Intermediate

The render props pattern involves a component that accepts a function as a prop (or as children), and calls it to determine what to render, sharing logic without inheritance or HOCs.

function MouseTracker({ render }) {
  const [pos, setPos] = useState({ x: 0, y: 0 });
  return (
    <div onMouseMove={e => setPos({ x: e.clientX, y: e.clientY })}>
      {render(pos)}
    </div>
  );
}

// Usage
<MouseTracker render={({ x, y }) => <p>{x}, {y}</p>} />

Hooks have largely replaced render props for sharing logic, but the pattern is still common in libraries like React Router and Formik.

Q41
What is a Higher-Order Component (HOC)?
Intermediate

A HOC is a function that takes a component and returns an enhanced component. It’s a compositional pattern for cross-cutting concerns (auth, logging, theming).

function withAuth(WrappedComponent) {
  return function AuthGuard(props) {
    const { isLoggedIn } = useAuth();
    if (!isLoggedIn) return <Redirect to="/login" />;
    return <WrappedComponent {...props} />;
  };
}

const ProtectedDashboard = withAuth(Dashboard);

HOCs should not mutate the wrapped component. Use a display name (AuthGuard.displayName) for better DevTools debugging.

Q42
Explain the Context + useReducer pattern for global state.
Intermediate

Combining Context and useReducer gives you a lightweight Redux-like global store without external libraries.

const StoreContext = createContext();

function storeReducer(state, action) {
  switch (action.type) {
    case 'LOGIN':  return { ...state, user: action.payload };
    case 'LOGOUT': return { ...state, user: null };
    default: return state;
  }
}

export function StoreProvider({ children }) {
  const [state, dispatch] = useReducer(storeReducer, { user: null });
  return (
    <StoreContext.Provider value={{ state, dispatch }}>
      {children}
    </StoreContext.Provider>
  );
}

export const useStore = () => useContext(StoreContext);
Q43
What is useImperativeHandle and when do you use it?
Intermediate

useImperativeHandle customizes the instance value exposed to parent refs via forwardRef, allowing you to expose only a limited API instead of the raw DOM node.

const FancyInput = forwardRef((props, ref) => {
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current.focus(),
    clear: () => { inputRef.current.value = ''; },
    // DOM node itself is NOT exposed
  }));

  return <input ref={inputRef} />;
});

// Parent can call: ref.current.focus() or ref.current.clear()
Q44
What is React Router? How do you set up basic routing?
Intermediate
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <nav>
        <Link to="/">Home</Link>
        <Link to="/about">About</Link>
        <Link to="/user/42">User</Link>
      </nav>
      <Routes>
        <Route path="/"          element={<Home />}         />
        <Route path="/about"     element={<About />}        />
        <Route path="/user/:id"  element={<UserProfile />}  />
        <Route path="*"          element={<NotFound />}      />
      </Routes>
    </BrowserRouter>
  );
}
Q45
How do you fetch data and handle loading/error states?
Intermediate
function PostList() {
  const [posts, setPosts]   = useState([]);
  const [status, setStatus] = useState('idle'); // idle|loading|success|error
  const [error, setError]   = useState(null);

  useEffect(() => {
    setStatus('loading');
    fetch('/api/posts')
      .then(r => { if (!r.ok) throw new Error(r.statusText); return r.json(); })
      .then(data => { setPosts(data); setStatus('success'); })
      .catch(err => { setError(err.message); setStatus('error'); });
  }, []);

  if (status === 'loading') return <Spinner />;
  if (status === 'error')   return <p>Error: {error}</p>;
  return posts.map(p => <Post key={p.id} post={p} />);
}
Q46
What is the difference between React.cloneElement and children props?
Intermediate

React.cloneElement lets you clone a React element and inject additional props or override existing ones, useful in compound component patterns.

function Tabs({ children, activeTab }) {
  return (
    <div>
      {React.Children.map(children, child =>
        React.cloneElement(child, {
          isActive: child.props.id === activeTab
        })
      )}
    </div>
  );
}
// Each Tab child now receives isActive without the parent knowing its internals

Modern alternative: use Context to share state inside compound components without cloneElement.

Q47
How do you debounce a search input in React?
Intermediate
function Search() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);

  useEffect(() => {
    if (!query) { setResults([]); return; }
    const timer = setTimeout(() => {
      fetchResults(query).then(setResults);
    }, 300); // 300ms debounce

    return () => clearTimeout(timer); // cancel if query changes
  }, [query]);

  return (
    <>
      <input value={query} onChange={e => setQuery(e.target.value)} />
      {results.map(r => <div key={r.id}>{r.title}</div>)}
    </>
  );
}
Q48
What are React DevTools and how do you use them for profiling?
Intermediate

React DevTools is a browser extension that adds a Components and Profiler panel to browser DevTools.

  • Components panel — inspect the component tree, view props/state/hooks, and highlight re-renders.
  • Profiler panel — record a session, then see which components rendered, how long each took (in ms), and why they re-rendered. Flame chart shows the render waterfall.

Workflow: Record → interact with the app → stop recording → look for unexpectedly frequent or slow renders → apply memo, useCallback, or structural fixes as needed.

Q49
What is the compound component pattern?
Intermediate

Compound components are a set of components that work together and share implicit state via Context. The parent manages state; children can access it without explicit props.

const AccordionContext = createContext();

function Accordion({ children }) {
  const [open, setOpen] = useState(null);
  return (
    <AccordionContext.Provider value={{ open, setOpen }}>
      <div>{children}</div>
    </AccordionContext.Provider>
  );
}

function Item({ id, children }) {
  const { open, setOpen } = useContext(AccordionContext);
  return (
    <div>
      <button onClick={() => setOpen(open === id ? null : id)}>Toggle</button>
      {open === id && children}
    </div>
  );
}

Accordion.Item = Item;

// Usage: <Accordion><Accordion.Item id="a">...</Accordion.Item></Accordion>
Q50
How do you implement infinite scroll in React?
Intermediate
function InfiniteList() {
  const [items, setItems]   = useState([]);
  const [page, setPage]     = useState(1);
  const sentinelRef         = useRef();

  useEffect(() => {
    fetchPage(page).then(data => setItems(prev => [...prev, ...data]));
  }, [page]);

  useEffect(() => {
    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) setPage(p => p + 1);
    });
    if (sentinelRef.current) observer.observe(sentinelRef.current);
    return () => observer.disconnect();
  }, []);

  return (
    <>
      {items.map(i => <Item key={i.id} data={i} />)}
      <div ref={sentinelRef} /> // invisible bottom sentinel
    </>
  );
}
Q51
What is code splitting and how do you do it in React?
Intermediate

Code splitting breaks your bundle into smaller chunks loaded on demand, reducing initial bundle size and TTI (Time to Interactive).

  • Component-level: React.lazy + dynamic import()
  • Route-level: Lazy-load each route component
  • Library-level: Webpack/Vite automatically split node_modules
// Route-level splitting
const Home    = lazy(() => import('./routes/Home'));
const Profile = lazy(() => import('./routes/Profile'));

<Suspense fallback={<Spinner/>}>
  <Routes>
    <Route path="/"        element={<Home/>}    />
    <Route path="/profile" element={<Profile/>} />
  </Routes>
</Suspense>
Q52
How does React handle accessibility (a11y)?
Intermediate

React supports full HTML accessibility attributes with camelCase naming. Key practices:

// aria-* attributes stay hyphenated
<button aria-label="Close modal" aria-expanded={isOpen}>✕</button>

// for/htmlFor association
<label htmlFor="email">Email</label>
<input id="email" type="email" />

// Focus management for modals
useEffect(() => { if (isOpen) closeButtonRef.current?.focus(); }, [isOpen]);

Tools: eslint-plugin-jsx-a11y, React Aria (Adobe), axe-core DevTools extension.

Q53
What is the useId Hook?
Intermediate

Introduced in React 18, useId generates a stable unique ID that is consistent between server and client renders — avoiding SSR hydration mismatches.

function FormField({ label }) {
  const id = useId(); // e.g. ":r1:"
  return (
    <>
      <label htmlFor={id}>{label}</label>
      <input id={id} />
    </>
  );
}

Do not use useId to generate keys for lists — use data IDs for that.

Q54
What are transitions in React 18?
Intermediate

startTransition marks a state update as non-urgent. React will defer it and keep the UI responsive for urgent updates (like typing).

import { startTransition, useTransition } from 'react';

function Search() {
  const [isPending, startTransition] = useTransition();
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);

  function handleChange(e) {
    setQuery(e.target.value); // urgent — update input immediately
    startTransition(() => {
      setResults(computeResults(e.target.value)); // non-urgent
    });
  }

  return (
    <>
      <input value={query} onChange={handleChange} />
      {isPending ? <Spinner/> : results.map(...)}
    </>
  );
}
Q55
How do you test React components? What tools do you use?
Intermediate

The standard stack: Vitest or Jest (test runner) + React Testing Library (RTL) for DOM-focused tests + Playwright/Cypress for end-to-end tests.

// Example RTL test
import { render, screen, fireEvent } from '@testing-library/react';

test('increments counter', () => {
  render(<Counter />);
  expect(screen.getByText('Count: 0')).toBeInTheDocument();
  fireEvent.click(screen.getByRole('button', { name: /increment/i }));
  expect(screen.getByText('Count: 1')).toBeInTheDocument();
});

RTL philosophy: test what the user sees (text, roles) not implementation details (state, refs).

Advanced Level

Q56
Explain React’s concurrent rendering and its benefits.
Advanced

Concurrent rendering (React 18) lets React prepare multiple versions of the UI simultaneously without blocking the main thread. Renders can be interrupted, paused, and resumed based on priority.

Key APIs:

  • createRoot — opt into concurrent mode
  • startTransition / useTransition — deprioritize non-urgent updates
  • useDeferredValue — defer a value to avoid blocking input
  • Suspense + data fetching — show fallbacks while async rendering

Benefit: heavy renders (large lists, complex charts) no longer freeze the UI — React keeps urgent interactions (typing, clicking) buttery smooth.

Q57
What is useDeferredValue? How does it compare to debouncing?
Advanced

useDeferredValue accepts a value and returns a deferred version that “lags behind” to allow more urgent renders to go first.

function SearchResults({ query }) {
  const deferredQuery = useDeferredValue(query);
  // stale deferredQuery during typing → React renders latest query first
  const results = expensiveFilter(deferredQuery);
  return results.map(r => <Result key={r.id} {...r} />);
}

vs debounce: debounce delays state updates on a fixed timer. useDeferredValue lets React schedule the update based on available CPU time — no artificial delay, and it starts updating as soon as the browser is idle.

Q58
What is Server-Side Rendering (SSR) with React and how does it work?
Advanced

With SSR, React renders components to HTML on the server and sends it to the browser. The client then “hydrates” — attaching event listeners to the existing HTML without re-rendering.

// Server (Node.js)
import { renderToString } from 'react-dom/server';
const html = renderToString(<App />);
res.send(`<html><body><div id="root">${html}</div></body></html>`);

// Client
import { hydrateRoot } from 'react-dom/client';
hydrateRoot(document.getElementById('root'), <App />);

Benefits: faster FCP, SEO-friendly. Drawbacks: TTFB increases, server load, hydration complexity. Frameworks: Next.js, Remix.

Q59
What are React Server Components (RSC)?
Advanced

React Server Components (introduced in React 18, popularized by Next.js 13+ App Router) run exclusively on the server. They can access databases and file systems directly, never ship JS to the client, and reduce bundle size.

  • Server Components — async, no state/hooks, zero client JS
  • Client Components'use client' directive, can use hooks and events
  • Shared Components — can render as either depending on where they’re imported
// app/page.tsx — Server Component (default in Next.js 13+)
async function Page() {
  const data = await db.query('SELECT * FROM posts'); // runs on server only
  return data.map(post => <PostCard key={post.id} post={post} />);
}
Q60
How does hydration work and what are hydration errors?
Advanced

Hydration is the process of attaching React’s event system to server-rendered HTML. React walks the existing DOM and matches it against the Virtual DOM tree. If they don’t match, React throws a hydration error and falls back to client rendering.

Common causes of hydration mismatch:

  • Rendering Date.now() or Math.random() differently server vs client
  • Using typeof window to conditionally render
  • Third-party scripts modifying the DOM before React hydrates
  • Invalid HTML nesting (e.g. <p><div></div></p>)

Fix: use suppressHydrationWarning for intentional mismatches (e.g., timestamps), or defer rendering until client with useEffect.

Q61
What is the Suspense data-fetching model (Suspense for Data Fetching)?
Advanced

A component “suspends” by throwing a Promise. React catches it, shows the nearest Suspense fallback, and retries rendering the component when the Promise resolves.

// Library creates a "resource" that throws a Promise
function wrapPromise(promise) {
  let status = 'pending', result;
  const p = promise.then(d => { status = 'success'; result = d; })
                   .catch(e => { status = 'error'; result = e; });
  return { read() {
    if (status === 'pending')  throw p;
    if (status === 'error')    throw result;
    return result;
  }};
}

// Component using the resource
function UserProfile({ resource }) {
  const user = resource.read(); // throws Promise if not ready
  return <div>{user.name}</div>;
}

In practice, frameworks like Next.js and libraries like TanStack Query implement this for you.

Q62
Build a virtualized list from scratch (windowing).
Advanced

Virtualization renders only the visible rows, keeping DOM nodes constant regardless of list size. Great for lists of 10,000+ items.

const ROW_HEIGHT = 40;

function VirtualList({ items }) {
  const [scrollTop, setScrollTop] = useState(0);
  const containerHeight = 400;
  const totalHeight = items.length * ROW_HEIGHT;

  const startIndex = Math.floor(scrollTop / ROW_HEIGHT);
  const visibleCount = Math.ceil(containerHeight / ROW_HEIGHT) + 1;
  const visibleItems = items.slice(startIndex, startIndex + visibleCount);

  return (
    <div
      style={{ height: containerHeight, overflowY: 'auto', position: 'relative' }}
      onScroll={e => setScrollTop(e.target.scrollTop)}
    >
      <div style={{ height: totalHeight }}>
        {visibleItems.map((item, i) => (
          <div
            key={item.id}
            style={{
              position: 'absolute',
              top: (startIndex + i) * ROW_HEIGHT,
              height: ROW_HEIGHT,
            }}
          >
            {item.name}
          </div>
        ))}
      </div>
    </div>
  );
}

In production, use react-window or @tanstack/react-virtual.

Q63
What is the Flux architecture? How does it relate to Redux?
Advanced

Flux is a unidirectional data-flow pattern from Facebook: Action → Dispatcher → Store → View → Action. Redux is an opinionated Flux implementation with a single store, pure reducer functions, and a rich middleware ecosystem.

// Redux flow
store.dispatch({ type: 'counter/increment' }); // Action
// Reducer: (state, action) => newState
// Subscribers re-render

Redux Toolkit (RTK) is now the official, recommended way to use Redux — it uses Immer internally so you can “mutate” state in reducers, and createSlice handles action type boilerplate.

Q64
What is Zustand and how does it compare to Redux?
Advanced

Zustand is a minimal, hook-based state manager. It has almost no boilerplate and works outside React components too.

import { create } from 'zustand';

const useStore = create(set => ({
  count: 0,
  increment: () => set(state => ({ count: state.count + 1 })),
}));

function Counter() {
  const { count, increment } = useStore();
  return <button onClick={increment}>{count}</button>;
}

vs Redux: Zustand is far less boilerplate, no Provider needed, subscribes components to only the slice of state they use. Redux RTK remains better for large teams needing strict conventions, time-travel debugging, and powerful middleware.

Q65
How do you optimize a React app that re-renders too frequently?
Advanced

Systematic approach:

  • Profile first — use React DevTools Profiler to find offending components before guessing.
  • Memoize componentsReact.memo skips re-renders when props are reference-equal.
  • Stable referencesuseCallback / useMemo prevent new object/function refs on each render.
  • Split Context — separate frequently-changing from infrequently-changing context values.
  • Colocate state — push state down; only subtrees that need it re-render.
  • Virtualize listsreact-window renders only visible rows.
  • Lazy load — code-split heavy sections, images, data.
  • Transitions — wrap non-urgent updates in startTransition.
Q66
What is flushSync in React 18?
Advanced

React 18 batches all state updates automatically (even in setTimeout and Promises). flushSync forces React to flush pending updates synchronously inside the callback — useful when you need DOM measurements immediately after a state update.

import { flushSync } from 'react-dom';

flushSync(() => {
  setItems([..items, newItem]);
});
// DOM is updated HERE, before the next line
listRef.current.lastChild.scrollIntoView();

Use sparingly — overuse hurts performance by defeating batching.

Q67
Implement a generic drag-and-drop list in React.
Advanced
function DnDList({ initialItems }) {
  const [items, setItems] = useState(initialItems);
  const dragIndex = useRef(null);

  function handleDragStart(index) { dragIndex.current = index; }

  function handleDrop(dropIndex) {
    const updated = [...items];
    const [removed] = updated.splice(dragIndex.current, 1);
    updated.splice(dropIndex, 0, removed);
    setItems(updated);
    dragIndex.current = null;
  }

  return (
    <ul>
      {items.map((item, i) => (
        <li
          key={item.id}
          draggable
          onDragStart={() => handleDragStart(i)}
          onDragOver={e => e.preventDefault()}
          onDrop={() => handleDrop(i)}
        >
          {item.label}
        </li>
      ))}
    </ul>
  );
}

For production: use @dnd-kit/core or react-beautiful-dnd for accessibility, touch support, and animation.

Q68
What is the stale closure problem in React Hooks?
Advanced

A stale closure occurs when a callback captures an old value from a previous render and doesn’t see the current state/props.

// ❌ Bug — count is stale inside setInterval callback
useEffect(() => {
  const id = setInterval(() => {
    setCount(count + 1); // always reads count=0
  }, 1000);
  return () => clearInterval(id);
}, []); // empty deps — effect never re-runs

// ✅ Fix — use functional updater
setCount(prev => prev + 1); // prev is always fresh

// ✅ Alternative — use a ref to track latest value
const countRef = useRef(count);
countRef.current = count;
// inside callback: use countRef.current
Q69
How do you implement optimistic updates in React?
Advanced

An optimistic update applies a change immediately in the UI before the server confirms it, then rolls back if the server returns an error.

async function toggleLike(postId) {
  // 1. Optimistically update UI
  setPosts(prev => prev.map(p =>
    p.id === postId ? { ...p, liked: !p.liked } : p
  ));

  try {
    await api.toggleLike(postId); // 2. Persist on server
  } catch {
    // 3. Roll back on failure
    setPosts(prev => prev.map(p =>
      p.id === postId ? { ...p, liked: !p.liked } : p // toggle back
    ));
    toast.error('Failed to update like');
  }
}

React 19 introduced useOptimistic for a built-in, first-class API for this pattern.

Q70
What is TanStack Query (React Query) and what problems does it solve?
Advanced

TanStack Query is a server-state management library. It handles: caching, background refetching, deduplication of requests, pagination, infinite scroll, optimistic updates, synchronization, and loading/error states — all declaratively.

import { useQuery, useMutation } from '@tanstack/react-query';

function Posts() {
  const { data, isLoading, error } = useQuery({
    queryKey: ['posts'],
    queryFn: () => fetch('/api/posts').then(r => r.json()),
    staleTime: 5 * 60 * 1000, // 5 minutes
  });

  if (isLoading) return <Spinner />;
  if (error) return <Error />;
  return data.map(p => <Post key={p.id} post={p} />);
}
Q71
How do you implement a real-time feature (e.g. live notifications) in React?
Advanced
function useNotifications(userId) {
  const [notifications, setNotifications] = useState([]);

  useEffect(() => {
    const ws = new WebSocket(`wss://api.example.com/ws?user=${userId}`);

    ws.onmessage = (event) => {
      const notif = JSON.parse(event.data);
      setNotifications(prev => [notif, ...prev]);
    };

    ws.onerror  = (e) => console.error('WebSocket error', e);
    ws.onclose  = ()  => console.log('WebSocket closed');

    return () => ws.close(); // cleanup on unmount / userId change
  }, [userId]);

  return notifications;
}

Alternatives: SSE (EventSource), long polling, or libraries like Socket.io / Ably.

Q72
What is the React DevTools Profiler API?
Advanced

The <Profiler> component lets you programmatically measure rendering performance in production builds.

import { Profiler } from 'react';

function onRenderCallback(id, phase, actualDuration, baseDuration) {
  sendToAnalytics({ id, phase, actualDuration, baseDuration });
}

<Profiler id="Navigation" onRender={onRenderCallback}>
  <Navigation />
</Profiler>

Parameters: id (label), phase (mount/update), actualDuration (time for this render), baseDuration (estimated without memo), startTime, commitTime.

Q73
How do you create a fully accessible modal dialog in React?
Advanced
function Modal({ isOpen, onClose, title, children }) {
  const dialogRef = useRef();

  useEffect(() => {
    if (!isOpen) return;
    dialogRef.current?.focus();
    const onKey = e => { if (e.key === 'Escape') onClose(); };
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [isOpen, onClose]);

  if (!isOpen) return null;

  return createPortal(
    <div role="dialog" aria-modal="true" aria-labelledby="modal-title">
      <div ref={dialogRef} tabIndex={-1}>
        <h2 id="modal-title">{title}</h2>
        {children}
        <button onClick={onClose} aria-label="Close">✕</button>
      </div>
    </div>,
    document.body
  );
}
Q74
What is state normalization and why is it important?
Advanced

State normalization stores entity data in a flat map (keyed by ID) rather than nested arrays. This avoids data duplication and makes updates O(1) instead of O(n).

// ❌ Denormalized — hard to update a specific post
{ posts: [{ id: 1, author: { id: 5, name: 'Alice' } }, ...] }

// ✅ Normalized — each entity stored once
{
  posts: { ids: [1], entities: { 1: { id: 1, authorId: 5 } } },
  users: { ids: [5], entities: { 5: { id: 5, name: 'Alice' } } }
}

Redux Toolkit’s createEntityAdapter automates this pattern. TanStack Query handles it automatically via query cache keying.

Q75
How do you measure and improve Core Web Vitals in a React app?
Advanced

Key CWV metrics and React-specific fixes:

  • LCP (Largest Contentful Paint) — SSR or SSG, preload hero image, eliminate render-blocking resources.
  • INP (Interaction to Next Paint) — debounce handlers, use startTransition, avoid long tasks, virtualize large lists.
  • CLS (Cumulative Layout Shift) — set explicit dimensions on images/iframes, avoid injecting content above existing content.
// Measure with web-vitals library
import { onINP, onLCP, onCLS } from 'web-vitals';
onINP(metric => sendToAnalytics(metric));
onLCP(metric => sendToAnalytics(metric));
Q76
What is the use Hook (React 19)?
Advanced

The use Hook (React 19) lets you read the value of a resource — a Promise or a Context — inside render. Unlike other hooks, use can be called inside conditionals and loops.

// Reading a Context with use (equivalent to useContext)
import { use } from 'react';

function Heading({ children }) {
  const level = use(LevelContext);
  return <{`h${level}`}>{children}</{`h${level}`}>;
}

// Reading a Promise (must be wrapped / cache)
function Comments({ commentsPromise }) {
  const comments = use(commentsPromise); // suspends until resolved
  return comments.map(c => <Comment key={c.id} comment={c} />);
}
Q77
How do you architect a large-scale React application?
Advanced

Key principles for large-scale React apps:

  • Feature-based folder structure — group by domain (features/auth, features/dashboard) not by type.
  • Clear layer separation — UI components → hooks/services → API layer.
  • Strict module boundaries — use barrel exports and enforce with ESLint import rules.
  • Micro-frontend or monorepo — NX/Turborepo for team scalability.
  • Design system — shared component library (Storybook) consumed by all features.
  • Typed contracts — TypeScript + Zod for runtime validation of API responses.
  • Testing pyramid — unit (hooks/utils), integration (RTL), e2e (Playwright).
Q78
What are Server Actions in Next.js / React 19?
Advanced

Server Actions let you call server-side functions directly from client components — without manually writing API routes. They’re marked with 'use server' and can be called from form actions or event handlers.

// actions.ts — runs on server
'use server';

export async function createPost(formData: FormData) {
  const title = formData.get('title') as string;
  await db.post.create({ data: { title } });
  revalidatePath('/posts');
}

// Client component
<form action={createPost}>
  <input name="title" />
  <button type="submit">Create</button>
</form>
Q79
What is Streaming SSR and how does it work in React 18?
Advanced

Streaming SSR uses renderToPipeableStream (Node.js) or renderToReadableStream (Edge) to stream HTML to the browser in chunks rather than waiting for the full page to render.

import { renderToPipeableStream } from 'react-dom/server';

res.setHeader('Content-Type', 'text/html');
const { pipe } = renderToPipeableStream(<App />, {
  onShellReady() { pipe(res); }, // send shell immediately
  onError(err) { console.error(err); }
});

Wrapped in Suspense, slow components don’t block the initial shell. The client progressively hydrates chunks as they stream in. Result: faster FCP + TTFB without sacrificing dynamic content.

Q80
How do you implement a micro-frontend with React?
Advanced

Micro-frontends decompose a large frontend into independently deployable apps owned by different teams. Common approaches with React:

  • Module Federation (Webpack 5 / Rspack) — dynamically load remote components at runtime.
  • iframes — strong isolation, simple, but limited UX/communication.
  • Custom Elements / Web Components — wrap React apps as standards-based elements.
  • Single-SPA — orchestrates multiple framework apps on one page.
// webpack.config.js (Host) — Module Federation
new ModuleFederationPlugin({
  remotes: {
    cart: 'cart@https://cart.example.com/remoteEntry.js',
  },
})

// In host app
const CartWidget = lazy(() => import('cart/CartWidget'));

Expert Level

Q81
Explain React’s scheduling and priority system in detail.
Expert

React uses a scheduler (the scheduler package) that assigns lanes and priorities to work. Work is queued in a min-heap and processed in priority order using cooperative scheduling (yielding to the browser event loop).

Priority levels (React 18 lanes):

  • SyncLaneflushSync, legacy mode. Always processes before paint.
  • InputContinuousLane — pointer/scroll events. Processed before next frame.
  • DefaultLane — normal setState. Batch and process asap.
  • TransitionLanestartTransition. Can be interrupted by higher-priority work.
  • OffscreenLane — pre-rendering hidden content.

The scheduler uses MessageChannel to schedule work asynchronously, yielding every ~5ms to let the browser handle input/paint.

Q82
How does React implement batching internally?
Expert

React wraps event handlers in batchedUpdates. In React 17 and earlier, this only applied inside React event handlers. In React 18, batching is automatic everywhere via a mechanism called automatic batching.

Internally: each setState call enqueues an update on the fiber’s updateQueue. React defers the re-render by scheduling work asynchronously. Only after the current execution context ends does React flush the queue and process all enqueued updates together in a single render pass.

Calling flushSync forces immediate synchronous flush of the queue.

Q83
What is the React Compiler (React Forget)?
Expert

The React Compiler (previously codenamed “React Forget”) is a Babel plugin developed by the React team that automatically memoizes components, hooks, and JSX expressions at compile time — eliminating the need for manual useMemo, useCallback, and React.memo.

It uses static analysis to identify values whose referential identity needs to be preserved, then inserts the correct memoization. It understands React’s rules of hooks and can prove safety of optimizations.

Released as part of React 19 with Meta running it in production on Instagram.com before public release. Opt in via babel config or Next.js config option.

Q84
How do you build a custom React renderer?
Expert

React’s reconciler (react-reconciler) is decoupled from the host environment. You implement a “host config” that defines how to create, update, and delete nodes in your custom target.

import Reconciler from 'react-reconciler';

const HostConfig = {
  createInstance(type, props) { return { type, props, children: [] }; },
  appendChildToContainer(container, child) { container.children.push(child); },
  commitUpdate(instance, _, __, ___, newProps) { instance.props = newProps; },
  removeChildFromContainer(container, child) { /* ... */ },
  supportsMutation: true,
  // ... ~30 other required methods
};

const MyRenderer = Reconciler.createContainer(HostConfig);

export function render(element, container) {
  MyRenderer.updateContainer(element, container);
}

Examples in the wild: React Three Fiber (WebGL/Three.js), React PDF, React Native, Ink (terminal).

Q85
How does React’s Context API work internally?
Expert

Internally, a Context object has a $$typeof symbol and stores the current value on the provider’s fiber during reconciliation.

When a Provider renders, React pushes the new value onto a context stack (a linked list of fiber nodes). When a useContext consumer renders, React walks up the fiber tree to find the nearest matching Provider and reads its current value.

When the Provider’s value changes, React propagates the change by marking all consumers as needing re-render (a “context propagation bailout” scan). This is O(n) in the subtree size, which is why splitting contexts and memoizing consumers matters for performance.

Q86
What are the gotchas of using React.memo with objects and functions?
Expert

React.memo uses shallow reference equality. Every render creates new object/array/function references, so memoization is defeated without useMemo/useCallback.

const Child = React.memo(({ style, onClick }) => <div style={style} onClick={onClick}>...</div>);

// ❌ New object on every Parent render — memo is useless
<Child style={{ color: 'red' }} onClick={() => doThing()} />

// ✅ Stable references
const style    = useMemo(() => ({ color: 'red' }), []);
const onClick  = useCallback(() => doThing(), []);
<Child style={style} onClick={onClick} />

Alternative: use the React Compiler which handles this automatically, or design components to accept primitive props.

Q87
How do you handle race conditions in data fetching with React?
Expert

Race conditions occur when a user triggers multiple requests and the last one resolves before an earlier one, displaying stale data. Solutions:

// Pattern 1: cleanup flag
useEffect(() => {
  let active = true;
  fetchData(id).then(data => { if (active) setData(data); });
  return () => { active = false; };
}, [id]);

// Pattern 2: AbortController
useEffect(() => {
  const controller = new AbortController();
  fetch(url, { signal: controller.signal })
    .then(r => r.json())
    .then(setData)
    .catch(e => { if (e.name !== 'AbortError') setError(e); });
  return () => controller.abort();
}, [url]);

TanStack Query handles race conditions automatically — it cancels in-flight queries when a newer request supersedes them.

Q88
How would you implement a feature-flag system in React?
Expert
// flags.ts
export const flags = {
  newDashboard: Boolean(process.env.NEXT_PUBLIC_FLAG_NEW_DASHBOARD),
};

// Hook
function useFlag(key) {
  const { user } = useAuth();
  const remoteFlags = useQuery({ queryKey: ['flags', user.id], queryFn: fetchFlags });
  return remoteFlags.data?.[key] ?? flags[key] ?? false;
}

// Usage
function App() {
  const showNewDash = useFlag('newDashboard');
  return showNewDash ? <NewDashboard /> : <OldDashboard />;
}

Production systems use services like LaunchDarkly, Statsig, or GrowthBook, which add targeting rules, A/B experimentation, kill switches, and analytics.

Q89
Implement a pub/sub event bus as a React hook.
Expert
// eventBus.ts
type Handler = (data: unknown) => void;
const listeners = new Map<string, Set<Handler>>();

export const eventBus = {
  on(event: string, handler: Handler) {
    if (!listeners.has(event)) listeners.set(event, new Set());
    listeners.get(event)!.add(handler);
    return () => listeners.get(event)!.delete(handler);
  },
  emit(event: string, data?: unknown) {
    listeners.get(event)?.forEach(h => h(data));
  }
};

// Hook
function useEvent<T>(event: string, handler: (data: T) => void) {
  const handlerRef = useRef(handler);
  handlerRef.current = handler;

  useEffect(() => {
    return eventBus.on(event, (data) => handlerRef.current(data as T));
  }, [event]);
}
Q90
How do you implement undo/redo in React state?
Expert
function useUndoRedo<T>(initial: T) {
  const [history, setHistory] = useState<T[]>([initial]);
  const [index, setIndex]     = useState(0);

  const current = history[index];

  const set = useCallback((newState: T) => {
    const next = history.slice(0, index + 1); // drop future states
    setHistory([...next, newState]);
    setIndex(next.length);
  }, [history, index]);

  const undo = () => setIndex(i => Math.max(0, i - 1));
  const redo = () => setIndex(i => Math.min(history.length - 1, i + 1));

  return { current, set, undo, redo,
    canUndo: index > 0,
    canRedo: index < history.length - 1
  };
}
Q91
How would you implement a multi-step wizard with URL-synced state?
Expert
const STEPS = ['info', 'payment', 'confirm'] as const;

function Wizard() {
  const [searchParams, setSearchParams] = useSearchParams();
  const stepParam = searchParams.get('step');
  const stepIndex = STEPS.indexOf((stepParam ?? 'info') as typeof STEPS[0]);
  const currentStep = STEPS[Math.max(0, stepIndex)];

  const [formData, setFormData] = useState({});

  function goTo(step: typeof STEPS[0]) {
    setSearchParams({ step });
  }

  function saveAndNext(data: object) {
    setFormData(prev => ({ ...prev, ...data }));
    const nextStep = STEPS[stepIndex + 1];
    if (nextStep) goTo(nextStep);
  }

  return (
    <>
      {currentStep === 'info'    && <InfoStep    onNext={saveAndNext} />}
      {currentStep === 'payment' && <PaymentStep onNext={saveAndNext} />}
      {currentStep === 'confirm' && <ConfirmStep data={formData}    />}
    </>
  );
}
Q92
How does React integrate with Web Workers?
Expert

Web Workers run JS in a background thread, off the main thread. React UI lives on the main thread, but you can offload CPU-heavy work (image processing, search indexing, AI inference) to a worker and communicate via postMessage.

// worker.ts
self.onmessage = ({ data }) => {
  const result = heavyComputation(data);
  self.postMessage(result);
};

// useWorker.ts
function useWorker(workerPath: string) {
  const workerRef = useRef<Worker>();
  useEffect(() => {
    workerRef.current = new Worker(workerPath, { type: 'module' });
    return () => workerRef.current?.terminate();
  }, [workerPath]);

  const compute = (data: unknown) => new Promise(resolve => {
    workerRef.current!.onmessage = ({ data }) => resolve(data);
    workerRef.current!.postMessage(data);
  });

  return { compute };
}
Q93
What is React’s act() testing utility and why is it important?
Expert

act() ensures that all state updates, effects, and re-renders are flushed before you make assertions in tests. Without it, tests may assert on stale DOM state.

import { act } from 'react';
import { render } from '@testing-library/react';

test('loads and displays data', async () => {
  await act(async () => {
    render(<DataLoader />);
  });
  // Now state updates + effects have all run
  expect(screen.getByText('Data loaded')).toBeInTheDocument();
});

React Testing Library wraps all its utilities (render, userEvent, fireEvent) in act automatically, which is why you typically don’t need to call it directly.

Q94
How do you implement a design system with React and CSS-in-JS?
Expert

A production design system typically combines:

  • Design tokens — CSS custom properties or JS objects for color, spacing, typography.
  • Primitive components — Box, Text, Stack, Grid with token-based props.
  • Compound components — Card, Modal, DataTable built from primitives.
  • Storybook — living documentation with interactive playground.
// tokens.ts
export const tokens = {
  colors: { primary: '#0066cc', danger: '#dc2626' },
  space: [0, 4, 8, 16, 24, 32, 48, 64],
};

// Button with variant system (using vanilla-extract or Tailwind CVA)
const button = cva('rounded font-medium', {
  variants: {
    intent: {
      primary: 'bg-blue-600 text-white',
      danger:  'bg-red-600 text-white',
      ghost:   'bg-transparent border',
    },
    size: { sm: 'px-2 py-1 text-sm', lg: 'px-6 py-3 text-lg' },
  },
  defaultVariants: { intent: 'primary', size: 'sm' },
});
Q95
How would you implement a collaborative real-time editor (like Google Docs) in React?
Expert

Key engineering challenges and solutions:

  • Conflict resolution — use Operational Transformation (OT) or CRDTs (Yjs, Automerge) to merge concurrent edits without conflicts.
  • Sync — WebSocket for real-time updates; CRDT diffs are small and efficient.
  • Awareness — broadcast cursor positions and user presence.
  • Offline support — CRDTs can merge divergent offline edits on reconnect.
  • React integration — bind Yjs doc changes to React state via y-react or custom useSyncExternalStore hook.
import * as Y from 'yjs';
import { WebsocketProvider } from 'y-websocket';

const ydoc = new Y.Doc();
const provider = new WebsocketProvider('wss://y.example.com', 'room-1', ydoc);
const yText = ydoc.getText('content');

// In component:
useSyncExternalStore(
  cb => { yText.observe(cb); return () => yText.unobserve(cb); },
  () => yText.toString()
);
Q96
What is useSyncExternalStore and when do you need it?
Expert

useSyncExternalStore (React 18) is the correct way to subscribe to external (non-React) stores inside components. It ensures consistency under concurrent rendering by providing a snapshot mechanism.

import { useSyncExternalStore } from 'react';

function useWindowWidth() {
  return useSyncExternalStore(
    (callback) => {
      window.addEventListener('resize', callback);
      return () => window.removeEventListener('resize', callback);
    },
    () => window.innerWidth,      // getSnapshot (client)
    () => 1024                   // getServerSnapshot (SSR)
  );
}

Use it when integrating with external state stores (Redux, Zustand, RxJS, browser APIs) to avoid tearing — inconsistent state during concurrent renders.

Q97
How does React’s Offscreen API (Activity) work?
Expert

The Offscreen component (API still stabilizing, called Activity in latest React canary) lets React pre-render trees that are not yet visible, or cache them when they’re hidden — without destroying their state.

<Offscreen mode="hidden">
  <ExpensiveTab />  // rendered but not visible, state preserved
</Offscreen>

Mode options:

  • visible — normal rendering
  • hidden — rendered off-screen, state preserved, effects paused
  • manual — developer controls visibility transitions

Enables: instant tab switching (pre-rendered), keepalive patterns, background rendering. Replaces the display: none hack that destroys React state.

Q98
Explain React’s tearing problem in concurrent mode and how it’s solved.
Expert

Tearing occurs when React renders a UI snapshot but an external store updates mid-render, causing different components to see different values of the same state — a visually inconsistent UI.

Scenario: Component A reads store version 1 → store updates to version 2 → Component B reads version 2 → they disagree on the same value.

React’s solution: useSyncExternalStore uses a two-phase “getSnapshot” check. After rendering, React verifies that all snapshots are still consistent. If not, it synchronously re-renders — trading some concurrency for consistency.

Libraries using legacy subscription patterns (e.g. old Redux useSelector) are vulnerable to tearing in concurrent mode until they migrate to useSyncExternalStore. RTK Query and modern Zustand handle this correctly.

Q99
How would you build a high-performance data grid with 100,000 rows in React?
Expert

A production-grade data grid for 100k rows requires multiple techniques in combination:

  • Row virtualization — @tanstack/react-virtual or react-window. Only render ~20-50 visible rows.
  • Column virtualization — virtual horizontal scrolling for wide tables.
  • Memoized row componentsReact.memo per row with stable props.
  • Immutable data structures — structural sharing for efficient diffing.
  • Lazy loading — paginated server requests or cursor-based fetching.
  • Web Worker offload — filtering, sorting, and aggregation off the main thread.
  • Canvas rendering — for extreme performance (AG Grid’s column virtualizer uses canvas for headers).

Production libraries: AG Grid, TanStack Table (headless), react-data-grid.

Q100
What does the future of React look like? (React 19 and beyond)
Expert

React 19 ships several transformative features that change how React apps are built:

  • React Compiler — automatic memoization; useMemo/useCallback/React.memo become largely unnecessary.
  • Server Components (stable) — zero-JS server-rendered components, direct data access, smaller bundles.
  • Server Actions (stable) — async server functions callable from clients, simplifying API route boilerplate.
  • use() Hook — read Promises and Contexts in render, even inside conditionals.
  • useOptimistic — first-class API for optimistic UI updates.
  • useFormStatus / useFormState — form state management tied to server actions.
  • Asset loading APIspreload, prefetchDNS, preinit for resource hints directly from components.
  • Activity (Offscreen) — keep-alive hidden subtrees with paused effects.

The direction: less client JS, better DX, compiler-driven optimization, and deeper server/client boundary awareness baked into the framework.