issue 117apr 27mmxxvi
est. 2017
Sun, 27 Apr 2026
vol. IX · no. 117
PapersAdda
placement intelligence, since 2017
868 briefs · 24 campuses · by reservation
verified offers · sourced from r/developersIndia
razorpay₹65.00 LPA· iit-d · sde-1google₹54.00 LPA· iiit-h · swe-imicrosoft₹49.50 LPA· iit-b · sdeatlassian₹38.00 LPA· nit-w · sde-1amazon₹44.20 LPA· bits-p · sde-1uber₹42.00 LPA· iit-kgp · sde-1razorpay₹65.00 LPA· iit-d · sde-1google₹54.00 LPA· iiit-h · swe-imicrosoft₹49.50 LPA· iit-b · sdeatlassian₹38.00 LPA· nit-w · sde-1amazon₹44.20 LPA· bits-p · sde-1uber₹42.00 LPA· iit-kgp · sde-1

Top 50 React Interview Questions 2026, Complete Guide with Solutions

25 min read
Interview Questions
Last Updated: 1 May 2026
Reviewed by PapersAdda Editorial

React developers are the most in-demand frontend engineers in India. Mid-level React roles pay ₹15-30 LPA at product startups; senior React/Next.js engineers at Flipkart, Swiggy, and Razorpay pull ₹35-65 LPA. The catch? With React 19 stable and Server Components becoming the default, the interview bar has jumped significantly, knowing useState and useEffect isn't enough anymore.

Flipkart, Swiggy, Razorpay, Adobe, Microsoft, CRED, and hundreds of funded startups are all hiring React engineers. This guide covers 50 battle-tested questions compiled from real interviews at these exact companies, from classic Hooks questions to bleeding-edge RSC patterns, with production-quality code examples for each.

Related: TypeScript Interview Questions 2026 | JavaScript Interview Questions 2026 | Microservices Interview Questions 2026


What to Expect in a React Interview in 2026

Modern React interviews are split into three stages:

StageFocusDuration
Phone ScreenCore Hooks, JSX, component lifecycle30–45 min
Technical RoundPerformance, state management, architecture60–90 min
System DesignSSR/RSC, data fetching strategy, large-scale UI45–60 min

Companies no longer accept "just working" answers. They want you to explain why, trade-offs, render behavior, memory implications. Keep that bar in mind as you study.


BEGINNER LEVEL (Questions 1–15)

Q1. What is the difference between a controlled and uncontrolled component?

Controlled component: React state drives the input value. Every keystroke triggers setState, making React the single source of truth.

Uncontrolled component: The DOM holds the value. You access it with useRef.

// Controlled
function ControlledInput() {
  const [value, setValue] = React.useState('');
  return (
    <input
      value={value}
      onChange={(e) => setValue(e.target.value)}
    />
  );
}

// Uncontrolled
function UncontrolledInput() {
  const inputRef = React.useRef(null);
  const handleSubmit = () => console.log(inputRef.current.value);
  return <input ref={inputRef} />;
}

When to use uncontrolled: file inputs, integrating with non-React libraries, performance-sensitive forms with hundreds of fields.


Q2. Explain the Rules of Hooks.

  1. Only call Hooks at the top level, never inside loops, conditions, or nested functions.
  2. Only call Hooks from React functions, functional components or custom Hooks.

React relies on the order of Hook calls to associate state correctly between renders. Breaking these rules causes React's internal linked list to desync, producing bugs that are extremely hard to trace.

// WRONG — Hook inside condition
function Bad({ isLoggedIn }) {
  if (isLoggedIn) {
    const [name, setName] = useState(''); // violates rule 1
  }
}

// CORRECT
function Good({ isLoggedIn }) {
  const [name, setName] = useState('');
  if (!isLoggedIn) return null;
  return <span>{name}</span>;
}

Q3. What does useState return and how does batching work in React 18+?

useState returns a tuple: [currentState, setterFunction]. The setter can accept a value or an updater function.

React 18 automatic batching: Before React 18, batching only occurred inside React event handlers. From React 18 onwards, ALL state updates are batched, including inside setTimeout, Promise.then, and native event listeners.

function Counter() {
  const [count, setCount] = React.useState(0);
  const [flag, setFlag] = React.useState(false);

  function handleClick() {
    // React 18: these batch into ONE re-render
    setCount(c => c + 1);
    setFlag(f => !f);
  }

  // In React 17, a setTimeout would cause 2 renders.
  // In React 18, it causes 1 render.
  setTimeout(() => {
    setCount(c => c + 1);
    setFlag(f => !f);
  }, 1000);
}

Use flushSync from react-dom if you need to opt out of batching.


Q4. What is useEffect and how do you clean it up?

useEffect lets you synchronize a component with an external system. The cleanup function runs before the effect re-runs and on unmount.

function useWebSocket(url) {
  const [messages, setMessages] = React.useState([]);

  React.useEffect(() => {
    const ws = new WebSocket(url);

    ws.onmessage = (event) => {
      setMessages(prev => [...prev, event.data]);
    };

    // Cleanup: close socket when url changes or component unmounts
    return () => {
      ws.close();
    };
  }, [url]); // re-run when url changes

  return messages;
}

Common pitfall: forgetting to cancel fetch calls or clear setInterval inside cleanup.


Q5. What is the difference between useMemo and useCallback?

HookMemoizesReturns
useMemoA computed valueThe value itself
useCallbackA function definitionThe function
function ExpensiveComponent({ items, onSelect }) {
  // Memoize expensive computation
  const sortedItems = React.useMemo(() => {
    return [...items].sort((a, b) => a.price - b.price);
  }, [items]);

  // Memoize callback so child doesn't re-render
  const handleClick = React.useCallback((id) => {
    onSelect(id);
  }, [onSelect]);

  return sortedItems.map(item => (
    <Item key={item.id} item={item} onClick={handleClick} />
  ));
}

useCallback(fn, deps) is equivalent to useMemo(() => fn, deps).


Q6. What is useRef and what are its two main use cases?

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

Use case 1: DOM access

function FocusInput() {
  const inputRef = React.useRef(null);

  React.useEffect(() => {
    inputRef.current.focus();
  }, []);

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

Use case 2: Storing mutable values that should NOT trigger re-renders (previous value, interval ID, etc.)

function Timer() {
  const intervalRef = React.useRef(null);
  const [count, setCount] = React.useState(0);

  const start = () => {
    intervalRef.current = setInterval(() => setCount(c => c + 1), 1000);
  };

  const stop = () => clearInterval(intervalRef.current);

  return (
    <>
      <p>{count}</p>
      <button onClick={start}>Start</button>
      <button onClick={stop}>Stop</button>
    </>
  );
}

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

React.memo is a HOC that skips re-rendering if props haven't changed (shallow comparison).

const ProductCard = React.memo(function ProductCard({ product, onAddToCart }) {
  console.log('Rendering ProductCard:', product.id);
  return (
    <div>
      <h3>{product.name}</h3>
      <button onClick={() => onAddToCart(product.id)}>Add to Cart</button>
    </div>
  );
});

// Custom comparison function
const ProductCardCustom = React.memo(ProductCard, (prevProps, nextProps) => {
  return prevProps.product.id === nextProps.product.id &&
         prevProps.product.price === nextProps.product.price;
});

When NOT to use: on components that almost always re-render with different props, or very simple/cheap components. The memoization itself has overhead.


Q8. Explain the Context API and its performance implications.

Context lets you share state without prop drilling. But every consumer re-renders when the context value changes.

const ThemeContext = React.createContext({ mode: 'light', toggle: () => {} });

function ThemeProvider({ children }) {
  const [mode, setMode] = React.useState('light');

  // IMPORTANT: memoize the value object to prevent unnecessary re-renders
  const value = React.useMemo(() => ({
    mode,
    toggle: () => setMode(m => m === 'light' ? 'dark' : 'light')
  }), [mode]);

  return (
    <ThemeContext.Provider value={value}>
      {children}
    </ThemeContext.Provider>
  );
}

function useTheme() {
  return React.useContext(ThemeContext);
}

Performance pitfall: putting everything in one context means a user profile change re-renders all theme consumers. Split contexts by update frequency.


Q9. What is key prop and why is it important?

React uses key to identify which items in a list changed, were added, or removed. It must be stable and unique among siblings.

// BAD: using index as key (causes bugs when list is reordered/filtered)
items.map((item, index) => <Item key={index} item={item} />)

// GOOD: use a stable unique ID
items.map(item => <Item key={item.id} item={item} />)

Real-world gotcha: when you use key to force a component to remount (reset its state), this is a valid pattern but intentional, not a crutch.


Q10. What is the difference between useLayoutEffect and useEffect?

useEffectuseLayoutEffect
TimingAfter paint (async)After DOM mutations, before paint (sync)
Use caseData fetching, subscriptionsDOM measurements, preventing flash
SSRSafeWarns on server
function Tooltip({ targetRef, children }) {
  const tooltipRef = React.useRef(null);

  // Must use useLayoutEffect to measure before paint
  React.useLayoutEffect(() => {
    const targetRect = targetRef.current.getBoundingClientRect();
    const tooltipEl = tooltipRef.current;
    tooltipEl.style.top = `${targetRect.bottom + 8}px`;
    tooltipEl.style.left = `${targetRect.left}px`;
  }, [targetRef]);

  return <div ref={tooltipRef} className="tooltip">{children}</div>;
}

Q11. How does React reconciliation (the diffing algorithm) work?

React uses a heuristic O(n) algorithm with two assumptions:

  1. Elements of different types produce different trees.
  2. Keys hint which child elements are stable across renders.

When a parent re-renders, React diffs the old and new virtual DOM trees. If element types are the same, React updates attributes in place. If types differ, React unmounts the old subtree and mounts the new one.

This is why changing a div to a span is expensive, the entire subtree unmounts. But changing just a className is cheap, only the DOM attribute updates.


Q12. What is useReducer and when is it better than useState?

useReducer is better when:

  • Next state depends on current state in complex ways
  • Multiple sub-values are related
  • State transitions need to be explicit and testable
const initialState = { count: 0, error: null, loading: false };

function reducer(state, action) {
  switch (action.type) {
    case 'INCREMENT': return { ...state, count: state.count + 1 };
    case 'SET_ERROR': return { ...state, error: action.payload, loading: false };
    case 'SET_LOADING': return { ...state, loading: true, error: null };
    default: throw new Error(`Unknown action: ${action.type}`);
  }
}

function Counter() {
  const [state, dispatch] = React.useReducer(reducer, initialState);

  return (
    <div>
      {state.loading && <Spinner />}
      {state.error && <Error message={state.error} />}
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>
        Count: {state.count}
      </button>
    </div>
  );
}

Q13. Explain error boundaries in React.

Error boundaries catch JavaScript errors in their child tree, log them, and display a fallback UI. They are class components implementing componentDidCatch and getDerivedStateFromError.

class ErrorBoundary extends React.Component {
  state = { hasError: false, error: null };

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

  componentDidCatch(error, errorInfo) {
    // Log to Sentry, Datadog, etc.
    logErrorToService(error, errorInfo.componentStack);
  }

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

// Usage
<ErrorBoundary fallback={<ErrorPage />}>
  <UserDashboard />
</ErrorBoundary>

React 19: use hook errors are also caught by error boundaries. React 19 also adds <ErrorBoundary> as a built-in component (no need to write class).


Q14. What is React's Strict Mode?

<React.StrictMode> enables extra developer warnings and intentionally double-invokes certain lifecycle methods and render functions to help you detect side effects. It runs only in development, never in production.

In React 18+, Strict Mode simulates mount → unmount → remount to check if your cleanup logic is correct. This is why you might see your useEffect fire twice in development.


Q15. What are synthetic events in React?

React wraps native browser events in SyntheticEvent objects that provide a normalized interface across browsers. In React 17+, synthetic events are no longer pooled (you no longer need event.persist()), and they're attached at the root rather than individual DOM nodes.


Solid on Q1-Q15? You've cleared the phone screen at most companies. The intermediate section covers RSC, Suspense, performance optimization, and state management, the topics that separate ₹15 LPA from ₹30 LPA+ offers.

INTERMEDIATE LEVEL, The Questions That Decide Your Offer (Questions 16–35)

Q16. What are React Server Components (RSC)?

RSC are components that render on the server and send serialized output (not HTML, but a special wire format) to the client. They can:

  • Access databases, file systems, and secrets directly
  • Import heavy server-only modules (no client bundle cost)
  • NOT use state, effects, or browser APIs
// app/products/page.tsx (Next.js 15 — this is a Server Component by default)
import { db } from '@/lib/db';

export default async function ProductsPage() {
  // Direct DB access — zero client bundle cost
  const products = await db.query('SELECT * FROM products LIMIT 20');

  return (
    <div>
      <h1>Products</h1>
      {products.map(p => (
        <ProductCard key={p.id} product={p} />
      ))}
    </div>
  );
}
// components/AddToCartButton.tsx
'use client'; // Client Component — has interactivity

import { useState } from 'react';

export function AddToCartButton({ productId }) {
  const [added, setAdded] = useState(false);
  return (
    <button onClick={() => setAdded(true)}>
      {added ? 'Added!' : 'Add to Cart'}
    </button>
  );
}

Q17. RSC vs CSR vs SSR vs SSG, comparison table

StrategyRenders onJS sent to clientGood for
CSRBrowserFull app bundleDashboards, apps behind auth
SSRServer (per request)Hydration bundleDynamic pages needing SEO
SSGBuild timeHydration bundleBlogs, docs, marketing pages
RSCServer (streaming)Only interactive partsProduct pages, data-heavy UIs
ISRBuild + revalidateHydration bundleEcommerce catalog

Q18. What is Suspense and how does it work with data fetching?

<Suspense> lets you declaratively specify a loading state while waiting for children to render.

import { Suspense } from 'react';

function UserProfile({ userId }) {
  return (
    <Suspense fallback={<ProfileSkeleton />}>
      <UserDetails userId={userId} />
      <Suspense fallback={<PostsSkeleton />}>
        <UserPosts userId={userId} />
      </Suspense>
    </Suspense>
  );
}

// UserDetails uses `use` hook to unwrap a promise (React 19)
function UserDetails({ userId }) {
  const user = use(fetchUser(userId)); // suspends until promise resolves
  return <h1>{user.name}</h1>;
}

With React Server Components, Suspense boundaries wrap async server components and stream content progressively.


Q19. Explain the use hook introduced in React 19.

The use hook is a new primitive that can read a value from a Promise or Context. Unlike other hooks, use can be called conditionally.

import { use } from 'react';

// Reading a promise (triggers Suspense)
function Message({ messagePromise }) {
  const message = use(messagePromise);
  return <p>{message}</p>;
}

// Reading context conditionally (unique to `use`)
function Greeting({ showTheme }) {
  if (showTheme) {
    const theme = use(ThemeContext); // conditionally reading context!
    return <h1 style={{ color: theme.primary }}>Hello</h1>;
  }
  return <h1>Hello</h1>;
}

Q20. What are React 19's new Actions and useActionState?

React 19 introduces Actions, async functions that can be passed to form action props and manage pending/error states natively.

import { useActionState } from 'react';

async function submitForm(prevState, formData) {
  try {
    await api.post('/contact', Object.fromEntries(formData));
    return { success: true, error: null };
  } catch (err) {
    return { success: false, error: err.message };
  }
}

function ContactForm() {
  const [state, action, isPending] = useActionState(submitForm, {
    success: false,
    error: null,
  });

  return (
    <form action={action}>
      <input name="email" type="email" required />
      <textarea name="message" required />
      {state.error && <p className="error">{state.error}</p>}
      {state.success && <p className="success">Message sent!</p>}
      <button type="submit" disabled={isPending}>
        {isPending ? 'Sending...' : 'Send'}
      </button>
    </form>
  );
}

Q21. Zustand vs Jotai vs Redux Toolkit, which and when?

LibraryModelBundleBest for
Redux ToolkitCentralized store + slices~14kBLarge teams, complex state, time-travel debugging
ZustandMultiple small stores~1kBMid-size apps, minimal boilerplate
JotaiAtomic state (bottom-up)~3kBFine-grained subscriptions, derived atoms
React Query / SWRServer state (async)~12kBAPI data, caching, background refetch
// Zustand store
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';

const useCartStore = create(
  devtools(
    persist(
      (set, get) => ({
        items: [],
        addItem: (product) =>
          set(state => ({ items: [...state.items, product] })),
        removeItem: (id) =>
          set(state => ({ items: state.items.filter(i => i.id !== id) })),
        total: () => get().items.reduce((sum, i) => sum + i.price, 0),
      }),
      { name: 'cart-storage' }
    )
  )
);

Q22. How do you implement code splitting in React?

import React, { lazy, Suspense } from 'react';

// Dynamic import — creates a separate chunk
const HeavyDashboard = lazy(() => import('./HeavyDashboard'));
const Reports = lazy(() => import('./Reports'));

function App() {
  const [view, setView] = React.useState('home');

  return (
    <Suspense fallback={<div>Loading...</div>}>
      {view === 'dashboard' && <HeavyDashboard />}
      {view === 'reports' && <Reports />}
    </Suspense>
  );
}

// Route-based splitting (React Router v7)
import { createBrowserRouter } from 'react-router';

const router = createBrowserRouter([
  {
    path: '/dashboard',
    lazy: () => import('./pages/Dashboard'),
  },
]);

Q23. What is the Compound Component pattern?

Compound components share implicit state through Context without exposing it as props, giving consumers a flexible API.

const AccordionContext = React.createContext(null);

function Accordion({ children }) {
  const [openIndex, setOpenIndex] = React.useState(null);
  return (
    <AccordionContext.Provider value={{ openIndex, setOpenIndex }}>
      <div className="accordion">{children}</div>
    </AccordionContext.Provider>
  );
}

Accordion.Item = function AccordionItem({ index, title, children }) {
  const { openIndex, setOpenIndex } = React.useContext(AccordionContext);
  const isOpen = openIndex === index;
  return (
    <div>
      <button onClick={() => setOpenIndex(isOpen ? null : index)}>
        {title}
      </button>
      {isOpen && <div>{children}</div>}
    </div>
  );
};

// Usage
<Accordion>
  <Accordion.Item index={0} title="Section 1">Content 1</Accordion.Item>
  <Accordion.Item index={1} title="Section 2">Content 2</Accordion.Item>
</Accordion>

Q24. Explain useTransition and useDeferredValue.

Both are concurrency features that let you mark updates as non-urgent so React can keep the UI responsive.

import { useTransition, useDeferredValue, useState } from 'react';

// useTransition: marks state update as non-urgent
function SearchPage() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  const [isPending, startTransition] = useTransition();

  const handleChange = (e) => {
    setQuery(e.target.value); // urgent — input stays responsive
    startTransition(() => {
      setResults(heavySearch(e.target.value)); // non-urgent
    });
  };

  return (
    <>
      <input value={query} onChange={handleChange} />
      {isPending ? <Spinner /> : <ResultsList results={results} />}
    </>
  );
}

// useDeferredValue: defers a value derived from urgent state
function FilteredList({ items, filter }) {
  const deferredFilter = useDeferredValue(filter);
  const filtered = items.filter(i => i.name.includes(deferredFilter));
  return <List items={filtered} />;
}

Q25. How do you handle forms in React, react-hook-form vs Formik vs native?

// react-hook-form (recommended for 2026 — minimal re-renders)
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';

const schema = z.object({
  email: z.string().email('Invalid email'),
  password: z.string().min(8, 'Min 8 characters'),
});

function LoginForm() {
  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting },
  } = useForm({ resolver: zodResolver(schema) });

  const onSubmit = async (data) => {
    await auth.login(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('email')} />
      {errors.email && <span>{errors.email.message}</span>}

      <input type="password" {...register('password')} />
      {errors.password && <span>{errors.password.message}</span>}

      <button type="submit" disabled={isSubmitting}>Login</button>
    </form>
  );
}

Q26. What is React's Concurrent Mode and the Fiber architecture?

React Fiber is the internal reconciliation engine rewritten in React 16. It represents work as a linked list of "fiber" nodes, enabling:

  • Interruptible rendering: React can pause work to handle higher-priority updates
  • Work prioritization: user input > transitions > background updates
  • Time slicing: spread rendering work across multiple frames

Concurrent Mode (enabled by createRoot in React 18+) exposes this to userland via useTransition, useDeferredValue, and Suspense.


Q27. Real-World Scenario: Infinite scroll with virtualization

import { useVirtualizer } from '@tanstack/react-virtual';
import { useInfiniteQuery } from '@tanstack/react-query';

function InfiniteProductList() {
  const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
    useInfiniteQuery({
      queryKey: ['products'],
      queryFn: ({ pageParam = 1 }) => fetchProducts(pageParam),
      getNextPageParam: (lastPage) => lastPage.nextPage,
    });

  const allItems = data?.pages.flatMap(p => p.items) ?? [];

  const parentRef = React.useRef(null);
  const virtualizer = useVirtualizer({
    count: hasNextPage ? allItems.length + 1 : allItems.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 80,
  });

  React.useEffect(() => {
    const lastItem = virtualizer.getVirtualItems().at(-1);
    if (!lastItem) return;
    if (lastItem.index >= allItems.length - 1 && hasNextPage && !isFetchingNextPage) {
      fetchNextPage();
    }
  }, [virtualizer.getVirtualItems(), hasNextPage]);

  return (
    <div ref={parentRef} style={{ height: '600px', overflow: 'auto' }}>
      <div style={{ height: virtualizer.getTotalSize() }}>
        {virtualizer.getVirtualItems().map(virtualRow => (
          <div
            key={virtualRow.key}
            style={{ transform: `translateY(${virtualRow.start}px)` }}
          >
            {allItems[virtualRow.index]
              ? <ProductCard product={allItems[virtualRow.index]} />
              : <Spinner />}
          </div>
        ))}
      </div>
    </div>
  );
}

Q28–Q35 (Quick Fire Round)

Q28. What is prop drilling and how do you solve it? Passing props through intermediate components that don't use them. Solutions: Context API, Zustand/Jotai, component composition (slot pattern).

Q29. What is the difference between null and undefined in JSX? Both null and undefined render nothing. false also renders nothing. 0 DOES render (gotcha!).

Q30. What does React.forwardRef do? Forwards a ref passed by a parent through to a DOM element or inner component inside a function component, which normally cannot accept ref as a prop.

Q31. What is the children prop? A special prop that contains whatever is placed between opening and closing tags. Can be a string, element, array, or function (render props pattern).

Q32. Explain React's startTransition API. Marks updates inside the callback as non-urgent transitions. Unlike useTransition, it doesn't provide isPending. Use useTransition when you need loading state.

Q33. What is the difference between React Router v6 and v7? React Router v7 merges with Remix. It adds framework-mode (like Next.js), type-safe routes, and server rendering built-in. Library-mode is backwards compatible.

Q34. How does React.StrictMode double-invoke renders affect real apps? Only in development. Ensure your component has no side effects in the render phase. Use useEffect for side effects, not the render body.

Q35. What is the purpose of React.Fragment? Groups multiple elements without adding a DOM node. Shorthand: <>...</>. Named fragments (<Fragment key={id}>) are needed when you need a key prop.


If you nail Q1-Q35, you're in the top 20% of React candidates. The advanced section is where ₹40 LPA+ senior frontend and full-stack offers are decided, performance at scale, custom hooks architecture, and system design.

ADVANCED LEVEL, The Senior Frontend Round (Questions 36–50)

Q36. How do you optimize a React app that renders a list of 10,000 items?

Three-pronged approach:

  1. Virtualization, only render items in viewport (TanStack Virtual, react-window)
  2. Memoization, React.memo on list items, useCallback for handlers
  3. Data normalization, store items in a Map/Record by ID, avoid O(n) lookups
// Combine all three
const MemoizedRow = React.memo(({ item, onSelect }) => (
  <div onClick={() => onSelect(item.id)}>{item.name}</div>
));

function VirtualList({ items }) {
  const onSelect = React.useCallback((id) => {
    console.log('selected', id);
  }, []);

  // ... virtualizer setup
  return virtualizer.getVirtualItems().map(vRow => (
    <MemoizedRow
      key={items[vRow.index].id}
      item={items[vRow.index]}
      onSelect={onSelect}
    />
  ));
}

Q37. What are custom Hooks and how do you write one?

Custom Hooks extract stateful logic into reusable functions. They must start with use.

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

  React.useEffect(() => {
    const controller = new AbortController();
    setLoading(true);

    fetch(url, { signal: controller.signal })
      .then(res => {
        if (!res.ok) throw new Error(res.statusText);
        return res.json();
      })
      .then(data => { setData(data); setLoading(false); })
      .catch(err => {
        if (err.name !== 'AbortError') {
          setError(err.message);
          setLoading(false);
        }
      });

    return () => controller.abort();
  }, [url]);

  return { data, loading, error };
}

Q38. Explain Server Actions in React 19 / Next.js 15.

Server Actions are async functions that run on the server, callable from client components. They replace most API routes for mutations.

// app/actions.ts
'use server';

import { revalidatePath } from 'next/cache';
import { db } from '@/lib/db';

export async function createPost(formData: FormData) {
  const title = formData.get('title') as string;
  await db.post.create({ data: { title, userId: auth().userId } });
  revalidatePath('/posts');
}
// app/new-post/page.tsx (Server Component)
import { createPost } from '../actions';

export default function NewPostPage() {
  return (
    <form action={createPost}>
      <input name="title" placeholder="Post title" required />
      <button type="submit">Create Post</button>
    </form>
  );
}

Q39. How do you implement optimistic updates with React Query?

const queryClient = useQueryClient();

const addTodoMutation = useMutation({
  mutationFn: (newTodo) => api.post('/todos', newTodo),
  onMutate: async (newTodo) => {
    // Cancel outgoing refetches
    await queryClient.cancelQueries({ queryKey: ['todos'] });
    // Snapshot previous value
    const previousTodos = queryClient.getQueryData(['todos']);
    // Optimistically update
    queryClient.setQueryData(['todos'], old => [...old, { ...newTodo, id: Date.now() }]);
    // Return snapshot for rollback
    return { previousTodos };
  },
  onError: (err, newTodo, context) => {
    // Rollback on error
    queryClient.setQueryData(['todos'], context.previousTodos);
  },
  onSettled: () => {
    queryClient.invalidateQueries({ queryKey: ['todos'] });
  },
});

Q40. What is hydration and what causes hydration errors?

Hydration is the process of attaching React event listeners to server-rendered HTML. React expects the client render to produce identical HTML to the server render.

Common causes of hydration mismatch:

  • typeof window !== 'undefined' checks that produce different output server vs client
  • Dates, random numbers, or Math.random() in render
  • Browser extensions injecting DOM nodes
  • Invalid HTML (e.g., <p> inside <p>)
// Fix: defer browser-only rendering
function ClientOnly({ children }) {
  const [mounted, setMounted] = React.useState(false);
  React.useEffect(() => setMounted(true), []);
  if (!mounted) return null;
  return children;
}

// Or use React 19's suppressHydrationWarning for known mismatches
<time suppressHydrationWarning dateTime={date.toISOString()}>
  {date.toLocaleString()}
</time>

Q41–Q50 Quick Advanced Round

Q41. What is the useImperativeHandle hook? Customizes the ref value exposed to parent components via forwardRef. Use it to expose a stable imperative API (e.g., .focus(), .scrollTo()) while keeping internal implementation private.

Q42. How do you implement a portal? ReactDOM.createPortal(children, domNode) renders children into a different DOM node (e.g., document.body) while keeping them in the React tree for context and events.

Q43. What is the Islands Architecture? A pattern where most of the page is static HTML, with interactive "islands" hydrated independently. Astro popularized this. React Server Components implement a similar idea natively.

Q44. How does Streaming SSR work in React 18+? renderToPipeableStream sends HTML progressively. Shell renders immediately; Suspense boundaries stream content as it resolves server-side. This improves TTFB without waiting for all data.

Q45. What is useOptimistic in React 19? A hook for optimistic UI updates. useOptimistic(state, updateFn) returns a temporary optimistic state that shows the expected outcome before the server confirms.

Q46. How do you debug performance issues in React? React DevTools Profiler → identify components with high render count or duration. why-did-you-render library → log unnecessary re-renders. Chrome Performance tab → identify long tasks.

Q47. What is the render prop pattern? A prop whose value is a function that returns JSX, giving the parent control over what to render while the child controls when. Used in libraries like React Table, Downshift.

Q48. What is useId used for? Generates stable unique IDs that are consistent between server and client renders. Use for accessibility attributes (htmlFor/id pairs, aria-describedby).

Q49. How do you handle race conditions in useEffect data fetching? Use an ignore flag or AbortController. Without it, slower requests that resolve after newer ones will overwrite state with stale data.

Q50. What are Module Federation and React Micro-Frontends? Webpack 5 Module Federation lets different React apps share components at runtime. Each "remote" exposes components; a "host" consumes them. Used by large enterprises to split frontends across teams with independent deployments.


Common React Mistakes, Avoid These and You're Ahead of 80% of Candidates

  1. Mutating state directly, state.items.push(x) instead of [...state.items, x]
  2. Missing cleanup in useEffect, causes memory leaks and stale closures
  3. Creating new objects/arrays in render, breaks memoization every render
  4. Using index as key, causes state bugs on list reorder/filter
  5. Over-using useEffect, many effects can be replaced with derived state or event handlers
  6. Not memoizing Context value, causes all consumers to re-render on parent render
  7. Fetching in useEffect without abort, race conditions and memory leaks
  8. Prop drilling past 2 levels, use Context or state management instead

You May Also Like

FAQ, Your React Career Questions, Answered

Q: Is Redux still relevant in 2026? Yes, for large enterprise apps with complex state, time-travel debugging needs, or strict team conventions. For most new projects, Zustand or TanStack Query is preferred.

Q: Should I use Next.js or Remix in 2026? Next.js 15 is the dominant choice. Remix merged into React Router v7 and is excellent for progressive enhancement and web standards. Both are production-ready.

Q: Are class components still asked in interviews? Rarely for greenfield roles, but legacy codebases still use them. Know componentDidMount, componentDidUpdate, componentWillUnmount, and how they map to Hooks.

Q: What is the best way to learn React Server Components? Build a Next.js 15 app with the App Router. The official React docs (react.dev) have excellent RSC documentation.

Q: Is TypeScript mandatory for React roles? TypeScript is expected at mid-to-senior level at most companies in 2026. Learn it, the ROI is high.

Q: How important is testing for React interviews? Mid-to-senior rounds often include testing questions. Know React Testing Library basics: render, screen, userEvent, waitFor.

Q: What state management should I learn first? Start with React's built-in state (useState, useReducer, Context). Then learn TanStack Query for server state. Then pick one of Zustand or Redux Toolkit.

Q: What React version should I target for interviews? React 19 is stable. Know React 18 concurrent features (useTransition, Suspense) and React 19 additions (use hook, Server Actions, useActionState, useOptimistic).


Next Steps: Practice building a full-stack app with Next.js 15, React 19 Server Components, and TanStack Query. Employers consistently test whether you can reason about rendering boundaries, not just write components.

React is the most in-demand frontend skill globally, and it's not going anywhere. Master these 50 questions, build a Next.js 15 project with RSC, and you'll walk into interviews with the confidence of a senior engineer.

Related Articles:

Explore this topic cluster

More resources in Interview Questions

Use the category hub to browse similar questions, exam patterns, salary guides, and preparation resources related to this topic.

Paid contributor programme

Sat this this year? Share your story, earn ₹500.

First-person experience reports help future candidates prep smarter. We pay verified contributors ₹500 via UPI per accepted story — with byline.

Submit your story →

Ready to practice?

Take a free timed mock test

Put what you learned into practice. Our mock tests match the 2026 pattern with timer, navigator, reveal, and score breakdown. No signup.

Start Free Mock Test →

Related Articles

More from PapersAdda

Share this guide: