Fast screens and clear state
Strong answers begin with measuring, then apply the least invasive fix. For state, separate server, URL, local and global state; most apps need much less global state than they think.
- Rendering costWhy components re-render and how to skip it.
- StateServer, URL, local and global state.
- React 19Actions, use() and Server Components.
Experienced React interviews ask why a component re-renders, how you would make a slow screen fast, and how you choose a state-management approach. In 2026 they also ask about React 19: Actions, the use API and Server Components.
1. When does a React component re-render?
When its state changes, when its parent re-renders (by default, even if props did not change), or when a context it reads changes. Re-renders are usually fine; they matter only when a component is expensive or renders thousands of times.
2. What do React.memo, useMemo and useCallback do?
React.memo skips re-rendering a component when its props are shallowly equal. useMemo caches a computed value between renders. useCallback caches a function so a memoised child does not see a “new” prop every time. They cost memory and comparisons, so use them where profiling shows a real gain.
const ProductList = React.memo(function ProductList({ items, onSelect }) { /* heavy list */ });
function Shop({ products, query }) {
const visible = useMemo(() => products.filter(p => p.name.includes(query)), [products, query]);
const handleSelect = useCallback(id => setSelected(id), []);
return <ProductList items={visible} onSelect={handleSelect} />;
}3. What is the React Compiler?
A build-time compiler that automatically memoises components and values, so you rarely need to write memo, useMemo or useCallback by hand. It relies on your code following the rules of React — pure rendering and no mutation of props or state.
4. How do you find and fix a slow React screen?
Profile with the React DevTools Profiler to see which components render often or take long. Typical fixes: move state down closer to where it is used, split contexts, memoise expensive children, virtualise long lists, lazy-load heavy routes with React.lazy and Suspense, and debounce expensive input handlers or use useDeferredValue.
const Reports = lazy(() => import('./Reports'));
<Suspense fallback={<Spinner />}>
<Reports />
</Suspense>5. How do you choose a state-management approach?
Split state by kind: server state (data from APIs) belongs in TanStack Query or a framework loader, which handles caching and refetching; URL state (filters, page) in the URL; local UI state in useState; and only truly global client state (cart, auth, theme) in context or a small store such as Zustand or Redux Toolkit.
6. What are Actions in React 19?
Actions are async functions used for transitions, typically form submissions. React tracks the pending state, errors and optimistic updates for you. useActionState gives you the result and pending flag, useFormStatus lets a child button know the form is submitting, and useOptimistic shows the expected result immediately.
function NewsletterForm() {
const [state, formAction, isPending] = useActionState(async (prev, formData) => {
const res = await subscribe(formData.get('email'));
return res.ok ? { message: 'Subscribed!' } : { message: 'Try again' };
}, { message: '' });
return (
<form action={formAction}>
<input name="email" type="email" required />
<button disabled={isPending}>{isPending ? 'Saving…' : 'Subscribe'}</button>
<p>{state.message}</p>
</form>
);
}7. What are React Server Components?
Components that run only on the server (in frameworks such as Next.js). They can read databases or files directly, send no JavaScript to the browser, and stream HTML. Interactive parts are Client Components marked with 'use client'. The result: smaller bundles and faster first loads.
// Server Component: no client JS, data fetched on the server
export default async function CoursePage({ params }) {
const course = await db.course.findUnique({ where: { slug: params.slug } });
return (
<>
<h1>{course.title}</h1>
<EnrollButton courseId={course.id} /> {/* 'use client' component */}
</>
);
}8. What does the use() API do?
use() reads the value of a promise or a context during render. With a promise, the component suspends until it resolves and the nearest Suspense boundary shows the fallback. Unlike other hooks it can be called inside conditions.
Remember
Key points
- Profile before memoising
Memoisation has costs too.
- Move state down
Fewer components re-render.
- Server state is a cache
Use a data-fetching library, not global stores.
- Server Components ship no JS
Interactivity lives in client components.
Interview drill
Follow-up questions
What the interviewer asks after your first answer. Turn on practice mode, answer each one aloud, then reveal.
-
1 Why might React.memo not help? Intermediate
If a prop is a new object, array or function on every render, the shallow comparison always fails. Stabilise props with useMemo/useCallback, or let the React Compiler do it.
-
2 What is useTransition for? Intermediate
It marks an update as non-urgent, so typing stays responsive while React prepares a slow update (such as filtering a big list) in the background.
-
3 How does context cause unnecessary re-renders? Intermediate
Every consumer re-renders when the context value changes. Split contexts by concern and memoise the value object.
-
4 What is hydration and what causes hydration errors? Advanced
Hydration attaches React to server-rendered HTML. Errors happen when the client renders different output — dates, random numbers or browser-only APIs during render.
-
5 How would you virtualise a list of 10,000 rows? Advanced
Render only visible rows plus a small buffer with a library such as TanStack Virtual, using fixed or measured row heights.