Top 50 React Interview Questions 2026, Complete Guide with Solutions
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:
| Stage | Focus | Duration |
|---|---|---|
| Phone Screen | Core Hooks, JSX, component lifecycle | 30–45 min |
| Technical Round | Performance, state management, architecture | 60–90 min |
| System Design | SSR/RSC, data fetching strategy, large-scale UI | 45–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.
- Only call Hooks at the top level, never inside loops, conditions, or nested functions.
- 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?
| Hook | Memoizes | Returns |
|---|---|---|
useMemo | A computed value | The value itself |
useCallback | A function definition | The 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?
useEffect | useLayoutEffect | |
|---|---|---|
| Timing | After paint (async) | After DOM mutations, before paint (sync) |
| Use case | Data fetching, subscriptions | DOM measurements, preventing flash |
| SSR | Safe | Warns 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:
- Elements of different types produce different trees.
- 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
| Strategy | Renders on | JS sent to client | Good for |
|---|---|---|---|
| CSR | Browser | Full app bundle | Dashboards, apps behind auth |
| SSR | Server (per request) | Hydration bundle | Dynamic pages needing SEO |
| SSG | Build time | Hydration bundle | Blogs, docs, marketing pages |
| RSC | Server (streaming) | Only interactive parts | Product pages, data-heavy UIs |
| ISR | Build + revalidate | Hydration bundle | Ecommerce 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?
| Library | Model | Bundle | Best for |
|---|---|---|---|
| Redux Toolkit | Centralized store + slices | ~14kB | Large teams, complex state, time-travel debugging |
| Zustand | Multiple small stores | ~1kB | Mid-size apps, minimal boilerplate |
| Jotai | Atomic state (bottom-up) | ~3kB | Fine-grained subscriptions, derived atoms |
| React Query / SWR | Server state (async) | ~12kB | API 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:
- Virtualization, only render items in viewport (TanStack Virtual, react-window)
- Memoization,
React.memoon list items,useCallbackfor handlers - 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
- Mutating state directly,
state.items.push(x)instead of[...state.items, x] - Missing cleanup in useEffect, causes memory leaks and stale closures
- Creating new objects/arrays in render, breaks memoization every render
- Using index as key, causes state bugs on list reorder/filter
- Over-using useEffect, many effects can be replaced with derived state or event handlers
- Not memoizing Context value, causes all consumers to re-render on parent render
- Fetching in useEffect without abort, race conditions and memory leaks
- Prop drilling past 2 levels, use Context or state management instead
You May Also Like
- React Interview Questions 2026
- Prompt Engineering Interview Questions 2026, Top 50 Questions with Answers
- Data Engineering Interview Questions 2026, Top 50 Questions with Answers
- Python Interview Questions 2026
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:
- TypeScript Interview Questions 2026, TypeScript is mandatory for React roles in 2026
- JavaScript Interview Questions 2026, the foundation React builds on
- Microservices Interview Questions 2026, understand the backend your React app consumes
- Golang Interview Questions 2026, Go + React is a powerful full-stack combo
- Docker Interview Questions 2026, containerize your Next.js deployments
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
ABB Interview Questions 2026 - Round-by-Round Guide
ABB interviews usually go beyond textbook answers. Panels expect clean thought process, structured communication, and...
Accenture Interview Questions 2026
Accenture is a leading global professional services company providing strategy, consulting, digital, technology, and...
Adobe Interview Questions 2026
Adobe is a multinational computer software company known for its creative, marketing, and document management solutions....
AMD Interview Questions 2026 - Round-by-Round Guide
AMD interviews usually go beyond textbook answers. Panels expect clean thought process, structured communication, and...
Atlassian Interview Questions 2026 - Round-by-Round Guide
Atlassian interviews usually go beyond textbook answers. Panels expect clean thought process, structured communication, and...
More from PapersAdda
How to Prepare for Google Coding Interview 2026
Airbnb Placement Papers 2026 – Questions, Answers & Complete Interview Guide
Cisco Placement Papers 2026 with Solutions, Aptitude, Technical & Coding
Flipkart Placement Papers 2026, Complete Guide with Solutions