[object Object]

31 React Interview Questions for All Levels (+ Answers)

This guide walks you through 30 React questions, from fundamentals to modern hooks and concurrency, so you can walk into your next interview confident and prepared.

POSTED ON DECEMBER 3, 2025

React is one of the most in-demand skills in web development, powering everything from startup dashboards to enterprise apps handling millions of users. 

If you’re preparing for a React interview, you need to understand modern features and frequent themes that come up in technical screenings.

This guide covers 30 interview questions from beginner to intermediate and advanced, with clear answers.

1. What is React, and how does it differ from manipulating the DOM directly? Provide a simple “Hello World” example.

  • Level: Beginner
  • Theme: Introduction & rendering

This question tests if you understand what React actually does and why you’d use it instead of plain JavaScript

Interviewers want to see that you grasp the fundamental difference between React’s declarative approach and manual DOM manipulation.

How to solve it

React is a JavaScript library for building user interfaces with reusable components. Instead of manually updating what users see on the page when data changes, you describe what the UI should look like, and React handles the updates.

The DOM (Document Object Model) is how browsers represent your webpage in memory—it’s the tree of HTML elements that makes up what users see. 

With plain JavaScript, you’d write code like this to show “Hello, world!”:

const element = document.getElementById('root');

element.innerHTML = '<h1>Hello, world!</h1>';

Every time you need to update something, you manually query the DOM and change it. This gets messy when you’re building complex interfaces with lots of moving parts.

React takes a different approach. You describe the UI you want, and React figures out how to update the DOM:

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(<h1>Hello, world!</h1>);

You call createRoot() once to set up where React should render, then call render() with your UI. 

Behind the scenes, React still updates the actual DOM, but it uses a diffing algorithm to decide which parts need to change. Instead of repainting everything, it compares the previous virtual tree with the new one and updates only the nodes that differ, which keeps renders fast even as your UI grows more complex.

React uses a virtual DOM—an in-memory representation of your UI—to figure out what changed. 

When you update something, React compares the new virtual DOM to the old one and only updates the parts of the real DOM that actually changed. 

All this makes updates faster and your code easier to reason about because you just describe the end result instead of writing step-by-step DOM manipulation.

2. What types of applications or problems does React excel at solving, and why do companies choose it for their projects?

  • Level: Introductory
  • Theme: React applications and use‑cases

This question tests whether you understand React’s strengths and real-world applications.

Interviewers want to see that you know why companies choose React over other frameworks.

How to solve it

React works well for single-page applications—websites that load once and update content without refreshing the page. Think Gmail or Facebook’s news feed. 

When you click something, new content appears instantly.

React is also a strong choice for dashboards, admin tools, and authentication flows that talk to a backend over APIs. Login forms, protected routes, and role-based views fit nicely into React’s component model, where each piece of UI can react to changes in user status and permissions.

Companies choose React because it offers:

  • Reusable components: Build a button once, use it everywhere. This cuts development time and keeps code consistent.
  • Fast updates: No page reloads needed. Content changes instantly when users interact with the interface.

3. What is JSX, and how does it differ from HTML? What rules apply when embedding expressions?

  • Level: Beginner
  • Theme: JSX basics

This question tests if you understand what JSX is and how it works under the hood. 

Interviewers want to see if you know the differences between JSX and regular HTML, since mixing them up can cause bugs.

How to solve it

JSX is a syntax extension that lets you write HTML-like code inside JavaScript files.

It looks like HTML, but it’s not. 

React compiles JSX into JavaScript function calls (React.createElement) behind the scenes.

Key differences from HTML:

  • Single root element: JSX must have one parent element. You can’t return multiple elements side-by-side without wrapping them in a fragment or div.
  • All tags must close: In HTML, <img> or <br> don’t need closing tags. In JSX, write <img /> and <br />.
  • camelCase attributes: Use className instead of class, htmlFor instead of for, and onClick instead of onclick.

You can embed JavaScript expressions inside curly braces {}:

function Greeting({ name, items }) {

  return (

    <div>

      <h1>Hello, {name}!</h1>

      <p>You have {items.length} items</p>

      <ul>

        {items.map(item => <li key={item.id}>{item.text}</li>)}

      </ul>

    </div>

  );

}

The curly braces let you compute values, access variables, or loop through arrays right inside your markup. 

This makes JSX declarative—you describe what the UI should look like based on your data, and React handles the updates.

4. What is a React component, and how do functional and class components differ? Which type is recommended in modern React?

  • Level: Beginner
  • Theme: Components & paradigms

This question tests whether you understand the building blocks of React applications and know the current best practices.

Interviewers want to see that you’re familiar with both types but understand why functional components are now preferred.

How to solve it

A component is a reusable piece of UI—like a custom HTML element you define yourself. 

Components can be written as functions or classes, but modern React uses functional components almost exclusively.

Functional components are just JavaScript functions that return JSX:

function Welcome({ name }) {

  return <h1>Hello, {name}</h1>;

}

That’s it. 

The function takes props and returns what should appear on the page. 

Functional components can use hooks like useState and useEffect to manage state and side effects.

Class components are written using JavaScript classes:

class Welcome extends React.Component {

  render() {

    return <h1>Hello, {this.props.name}</h1>;

  }

}

They extend React.Component and must implement a render() method. Class components also use lifecycle methods like componentDidMount and componentDidUpdate instead of hooks, and they require understanding this binding.

In a typical class component, you often define a constructor to initialize the current state and bind event handlers, then rely on the component lifecycle methods to react to updates. Those methods eventually call APIs like setState behind the scenes; some guides casually refer to that update step as setstate, even though the actual method name uses camelCase as setState.

They’re more verbose and make sharing logic between components harder—you need patterns like higher-order components or render props instead of simple custom hooks.

Modern React recommends functional components because they’re simpler, and hooks make reusing code easier.

Tip: You’ll still see class components in older codebases and for error boundaries (React doesn’t have a hook-based alternative yet). But when writing new code, use functional components.

5. What is the difference between state and props, and when would you use each?

  • Level: Beginner
  • Theme: State vs props

This question checks if you understand how data flows in React. 

It’s fundamental—mixing up state and props leads to bugs and confused component design.

How to solve it

Props are information a parent component gives to a child, and they can’t be changed. State is data a component stores for itself and can update when something happens.

The button line: Use props to pass data down, use state to track changes inside a component.

Think of props like function arguments. When you create a Welcome component, the parent decides what to pass in:

function Welcome({ name }) {

  return <h1>Hello, {name}</h1>;

}

<Welcome name="Alice" />

The Welcome component receives name but can’t change it. That’s the whole point—props flow in one direction, from parent to child. This makes your components predictable and reusable.

State is different. It lives inside a component and tracks things that change. 

A counter is the classic example:

function Counter() {

  const [count, setCount] = useState(0);

  return (

    <div>

      <p>Count: {count}</p>

      <button onClick={() => setCount(count + 1)}>Increment</button>

    </div>

  );

}

When someone clicks the button, setCount updates the value and React re-renders the component. The counter owns this data—no parent component is involved.

So when do you use each? 

Use props when you’re passing data from a parent or configuring how a component works. Use state when the component needs to track its own changing data—form inputs, toggle states, fetched data, anything that updates in response to user actions.

Tip: If sibling components need to share data, lift the state up to their common parent and pass it down as props to both.

6. How do you conditionally render components in React? Describe at least two techniques.

  • Level: Beginner
  • Theme: Conditional rendering & control flow

This question tests your understanding of how React handles conditional logic.

Interviewers want to see that you know multiple approaches and can pick the right one for different situations.

How to solve it

React components return different JSX based on conditions. 

You have several options:

Ternary operator for choosing between two elements:

function Greeting({ isLoggedIn }) {

  return isLoggedIn ? <Dashboard /> : <LoginForm />;

}

Logical AND operator to render something only when a condition is true:

function Header({ isLoggedIn }) {

  return (

    <nav>

      <Logo />

      {isLoggedIn && <LogoutButton />}

    </nav>

  );

}

Early return to handle complex conditions:

function UserProfile({ user }) {

  if (!user) return <div>Loading...</div>;

  if (user.isBlocked) return <div>Access denied</div>;

  return <div>Welcome, {user.name}</div>;

}

Pick based on your needs. 

Tip: Ternaries work for simple either/or cases. AND operators work when you only show something conditionally. Early returns keep complex logic readable.

7. What are React fragments, and why might you use them instead of wrapping elements in a <div>? Provide a simple example.

  • Level: Beginner
  • Theme: Fragments & JSX syntax

This question checks if you understand how to group elements without adding unnecessary HTML tags.

It shows you care about keeping your HTML structure clean.

How to solve it

Fragments let you return multiple elements from a component without wrapping them in an extra <div>

This matters because that extra wrapper can break your layout or create invalid HTML.

Remember, React components must return a single element. 

Say you’re building a card component with a title and description. Your first instinct might be to wrap them in a <div>:

function Card() {

  return (

    <div>

      <h1>Title</h1>

      <p>Description</p>

    </div>

  );

}

The problem is that <div> becomes part of your actual page HTML.

If you’re using Flexbox or CSS Grid where the parent expects direct children, that wrapper breaks your layout. 

Or if you’re rendering table rows, a <div> inside <tr> creates invalid HTML that browsers will try to fix (and probably mess up).

Fragments give you a way out. 

Write <> and</> instead:

function Card() {

  return (

    <>

      <h1>Title</h1>

      <p>Description</p>

    </>

  );

}

React groups these elements internally, but when the HTML reaches the browser, you just get the <h1> and <p> as siblings.

The bottom line: no wrapper, no layout problems. 

Tip: If you need to add a key prop (like when rendering lists), use the full syntax: <React.Fragment key={item.id}>.

8. How do you destructure props in a functional component, and how can you provide default values? Provide an example.

  • Level: Beginner
  • Theme: Props & ES6 syntax

This question tests your knowledge of modern JavaScript and whether you write clean, readable component code. 

Destructuring is standard practice in React—not using it makes your code harder to follow.

How to solve it

Destructure props in your function parameters by wrapping them in curly braces. Add = value after any prop to set a default if it’s not passed in.

Without destructuring, you have to write props. every time you access a value:

function Button(props) {

  return <button onClick={props.onClick}>{props.label}</button>;

}

Destructuring pulls the props out in the function signature so you can use them directly:

function Button({ label, onClick }) {

  return <button onClick={onClick}>{label}</button>;

}

This makes it immediately obvious which props the component uses. If someone forgets to pass the label prop, your button text shows undefined

You can prevent this by adding a default value:

function Button({ label = 'Submit', onClick }) {

  return <button onClick={onClick}>{label}</button>;

}

Now <Button onClick={handleClick} /> automatically displays “Submit” when no label is provided. The = ‘Submit’ syntax handles the fallback without needing conditional logic in your component body.

For class components, destructure inside the render method since props come from this .props:

class UserCard extends React.Component {

  render() {

    const { name, age = 0 } = this.props;

    return <p>{name} ({age})</p>;

  }

}

9. Describe a scenario where composition is preferred over inheritance in React. Why is composition considered a core principle?

  • Level: Beginner
  • Theme: Component design

This question tests whether you understand how React builds UIs differently from traditional object-oriented programming.

Interviewers want to see that you think in terms of combining independent pieces rather than creating class hierarchies.

How to solve it

React builds UIs by composing smaller components into bigger ones, not by having components inherit from parent classes. This keeps components independent and reusable.

The inheritance approach:

In languages like Java or C++, you might create a BasePage class with shared methods like render() and getTitle(). Then HomePage and AboutPage inherit from it and override methods when they need different behavior.

This creates all sorts of issues. 

Change something in BasePage and every child class might break. 

Add a feature that only one page type needs? You either bloat the base class or create complex inheritance chains.

The composition approach:

React arranges independent components instead:

function Page() {

  return (

    <div>

      <Header />

      <Content />

      <Footer />

    </div>

  );

}

Each component stands alone. 

Need a compact header for mobile?

Just swap in a different component:

function MobilePage() {

  return (

    <div>

      <CompactHeader />

      <Content />

      <Footer />

    </div>

  );

}

In other words, components communicate through props and stay testable in isolation. 

This flexibility is why React’s documentation actively discourages inheritance.

10. How would you structure a React application to facilitate testability and scalability? Discuss file organisation, naming conventions, and separation of concerns.

  • Level: Beginner
  • Theme: Architecture and best practices

This question checks if you know how to organize a React project as it grows. 

Interviewers want to see that you can structure code so new features don’t break existing ones and tests stay manageable.

How to solve it

Group files by feature instead of by type. 

For each feature, keep its components, hooks, and tests in one folder. Use descriptive names and separate components that display things from components that handle logic.

The most efficient solution is to group related code together:

features/

  user-management/

    UserList.jsx

    UserDetail.jsx

    useUserData.js

    UserList.test.js

Follow these best practices:

  • Use clear names like UserList.jsx instead of list.js.
  • Separate components that just display things (presentational) from components that handle logic (container). 
  • When multiple components need the same code, create a custom hook like useUserData instead of repeating it.

11. How would you style a header component based on a given design specification (e.g., from Figma), and what tasks would you perform?

  • Level: Beginner
  • Theme: Styling & UI design

Many real-world interviews ask you to translate a design mockup into a working component. 

This tests your ability to turn visual specs into clean, functional code.

How to solve it

Start by examining the design and noting the details:

  • Navigation links needed (e.g., /, /products, /documentation, /pricing)
  • Spacing, colors, and typography specifications
  • Any interactive states, like hover effects

Create a Header component using semantic HTML, for example:

function Header() {

  return (

    <nav>

      <a href="/">Home</a>

      <a href="/products">Products</a>

      <a href="/documentation">Docs</a>

      <a href="/pricing">Pricing</a>

    </nav>

  );

}

Then, you’d need to implement the styles with CSS modules or a CSS-in-JS library to match the design pixel-perfect. 

Tip: Use useState only if the header has an interactive state, like a mobile menu. Otherwise, keep it stateless.

12. What measures do you take to make a React component accessible (a11y), and why is accessibility important?

  • Level: Beginner
  • Theme: Accessibility

This question tests whether you consider users with disabilities when building interfaces. 

Accessibility is a legal requirement in many cases and makes your app usable by everyone.

How to solve it

Accessibility makes sure users with disabilities can navigate and use your app. Follow these practices:

  • Use semantic HTML: Use <button> instead of <div> for clickable elements, <nav> for navigation, <main> for main content
  • Label inputs: Connect labels to inputs with <label htmlFor=”email”>
  • Enable keyboard navigation: Ensure users can tab through interactive elements with tabIndex
  • Add ARIA attributes: Use aria-label, aria-describedby for custom components that screen readers need to understand
  • Check color contrast: Ensure text is readable against backgrounds

Tip: Automated tools like axe-core catch common issues. Manual testing with a keyboard and screen reader can also help you find hidden problems.

13. How would you integrate a third‑party library (e.g., D3 or Google Maps) into a React component?

  • Level: Beginner
  • Theme: Integration & side effects

This question checks if you know how to mix React’s declarative approach with libraries that manipulate the DOM directly. 

Many real-world apps need to integrate charting libraries, maps, or other tools that weren’t built for React.

How to solve it

Create a wrapper component that uses useRef to reference a DOM element. 

In useEffect, instantiate the third-party library and attach it to that element:

function MapComponent() {

  const mapRef = useRef(null);

  useEffect(() => {

    // Initialize the library

    const map = new google.maps.Map(mapRef.current, {

      center: { lat: 40.7, lng: -74.0 },

      zoom: 10

    });

    // Cleanup when component unmounts

    return () => {

      // Clean up the map instance if needed

    };

  }, []);

  return <div ref={mapRef} style={{ width: '100%', height: '400px' }} />;

}

When you explain this pattern in an interview, call out that the useEffect hook runs after React has painted the UI, and that the empty dependencies array ([]) tells React to run the effect only once on mount. If you passed variables into that array, React would re-run the effect whenever those values change, which is how you keep third-party libraries in sync with your component.

Tip: The cleanup function in useEffect’s return prevents memory leaks when the component unmounts. This pattern isolates imperative code from React’s declarative rendering.

14. How do you manage form inputs in React using controlled components? Provide an example.

  • Level: Beginner
  • Theme: Forms & controlled inputs

This question tests if you understand how React handles form inputs differently from plain HTML. 

Hiring managers want to see that you know how to keep form values in sync with component state.

How to solve it

In a controlled component, React state controls the input value. 

You can store the value in state, connect it to the input’s value prop, and update it when the user types.

Here’s a simple contact form:

function ContactForm() {

  const [name, setName] = useState('');

  return (

    <form>

      <input 

        value={name} 

        onChange={e => setName(e.target.value)} 

      />

      <p>Hello, {name}</p>

    </form>

  );

}

The input’s value is tied to the name state variable. 

When someone types, onChange fires and updates the state. React re-renders, and the input shows the new value. State always determines what the input displays—that’s why it’s “controlled.”

This makes validation and transformations simple. 

Want to convert input to uppercase? Use setName(e.target.value.toUpperCase()). Want to disable submit until they enter 3 characters? Check name.length >= 3.

Tip: Uncontrolled components exist too—they let the input manage its own value, which you can access through a ref. But controlled components remain the standard approach in React.

15. How do you render a list of items in React, and why is it important to supply a key prop?

  • Level: Beginner
  • Theme: Lists & keys

This question tests if you know how to render dynamic lists and understand why keys matter. 

Using keys incorrectly is a common mistake that causes hard-to-debug issues.

How to solve it

Use JavaScript’s Array.map() to transform an array into JSX elements.

Each element needs a unique key prop so React can track which items changed, were added, or were removed.

Here’s a simple example:

const items = ['apple', 'banana', 'orange'];

const list = items.map(item => <li key={item}>{item}</li>);

return <ul>{list}</ul>;

The key prop helps React identify each item between renders. 

When the list updates, React uses keys to figure out what changed. 

Without keys, React has to guess which items are which, leading to problems like losing input focus, incorrect animations, or components showing the wrong data.

Tip: Don’t use array indices as keys if your list can change order or items can be added/removed:

// Bad - indices change when you reorder items

items.map((item, index) => <li key={index}>{item}</li>)

// Good - use stable IDs

items.map(item => <li key={item.id}>{item.name}</li>)

When you reorder items, the indices change but the actual items don’t. React sees the same key (like 0) but different content, so it thinks the item changed instead of moved.

This causes React to update the wrong DOM nodes.

Tip: Use stable, unique identifiers like database IDs for keys. If your data doesn’t have IDs, generate them when you create the items—just don’t generate them during render or they’ll be different every time.

16. How would you build a to‑do list (task manager) with CRUD operations using React hooks, and what key considerations ensure a scalable solution?

  • Level: Intermediate
  • Theme: Real-world challenge & state management

This is a common take-home or live coding challenge. 

Interviewers want to see you handle state, user input, and basic operations that most apps need.

How to solve it

Store tasks in useState as an array of objects. Each task needs an id, text, and completed flag:

const [tasks, setTasks] = useState([]);

// Create

const addTask = (text) => {

  const newTask = { id: Date.now(), text, completed: false };

  setTasks([...tasks, newTask]);

};

// Read (render the array)

tasks.map(task => <div key={task.id}>{task.text}</div>);

// Update

const toggleTask = (id) => {

  setTasks(tasks.map(task => 

    task.id === id ? { ...task, completed: !task.completed } : task

  ));

};

// Delete

const deleteTask = (id) => {

  setTasks(tasks.filter(task => task.id !== id));

};

Use controlled inputs for adding or editing tasks. Give each task a stable key (use the id, not array index).

For a more advanced solution, you can move your task logic into a reducer using the useReducer hook so all changes funnel through a single function. In production apps, those tasks might also sync to a backend API that sends and receives JSON, so mentioning API design and persistence shows you can scale the same pattern beyond a toy example.

Tip: To persist tasks between sessions, save to localStorage in a useEffect and load on mount. The React JS machine-coding repository includes a to-do list project for practicing this exact pattern.

17. Why does React encourage immutability, and how would you update a deeply nested state object without mutation?

  • Level: Intermediate
  • Theme: Immutability & state updates

This question checks if you understand how React detects changes and why mutating state directly causes bugs.

How to solve it

React encourages immutability (not changing existing objects) because it detects changes by comparing object references. 

When you mutate state directly, the reference stays the same, and React thinks nothing changed. 

To update nested state, create new objects at each level using the spread operator or use a library like Immer.

Here’s what goes wrong when you mutate:

// Wrong - mutates the array

const addItem = () => {

  user.items.push(newItem);

  setUser(user); // Same reference, React misses the change

};

Create a new array instead:

// Right - new reference

const addItem = () => {

  setUser({

    ...user,

    items: [...user.items, newItem]

  });

};

For nested objects, copy at each level:

setUser({

  ...user,

  profile: {

    ...user.profile,

    address: {

      ...user.profile.address,

      city: 'New York'

    }

  }

});

18. How do you prioritize state updates with useTransition, and how does startTransition differ from useTransition?

  • Level: Intermediate
  • Theme: Concurrency & hooks

This question tests your knowledge of React’s concurrency features for keeping UIs responsive during heavy updates.

How to solve it

You prioritize updates by wrapping expensive state changes in startTransition, which marks them as low-priority so React can interrupt them for urgent events. 

useTransition is a hook that returns [isPending, startTransition], while the standalone startTransition() function works the same way but doesn’t provide the isPending flag.

function SearchResults() {

  const [isPending, startTransition] = useTransition();

  const [query, setQuery] = useState('');

  const [results, setResults] = useState([]);

  const handleSearch = (value) => {

    setQuery(value); // Urgent update

    startTransition(() => {

      setResults(expensiveFilter(value)); // Low-priority, can be interrupted

    });

  };

  return (

    <>

      <input value={query} onChange={e => handleSearch(e.target.value)} />

      {isPending && <Spinner />}

      <ResultsList items={results} />

    </>

  );

}

The input updates immediately while filtering happens in the background. 

Remember that hooks like useTransition still have to be called at the top level of your component function, just like useState or useEffect. You can’t wrap the hook call itself in conditionals or loops, even though you can wrap the state updates you pass into startTransition.

Tip: The isPending flag lets you show loading UI. Use the standalone startTransition() when you’re outside a component context, like in event handlers or data libraries—it works the same way but without the pending flag.

19. How does the useDeferredValue hook help keep the UI responsive during expensive renders?

  • Level: Intermediate
  • Theme: Concurrency & hooks

This question checks if you understand another concurrency tool for handling expensive computations without blocking the UI.

How to solve it

useDeferredValue keeps the UI responsive by returning a lagged version of a value. 

React continues showing the old value while it renders the new one in the background, so expensive updates don’t block user interactions.

function SearchPage({ query }) {

  const deferredQuery = useDeferredValue(query);

  return (

    <>

      <input value={query} onChange={handleChange} />

      <ExpensiveList query={deferredQuery} />

    </>

  );

}

When the query changes, the input updates immediately, but deferredQuery keeps the old value. 

React works on updating the list in the background. 

Tip: This is useful when you’re filtering large lists, displaying complex charts, or doing any computation that takes time—the user can keep typing while React processes the update.

20. What is concurrent rendering, and how does React’s scheduler decide which updates to prioritize?

  • Level: Intermediate
  • Theme: Concurrency

This question tests if you understand how React handles multiple updates at once and keeps the UI responsive.

How to solve it

Concurrent rendering breaks rendering work into small chunks that can be paused and resumed. 

React’s scheduler gives urgent updates (like typing) higher priority than non-urgent ones (like filtering results).

React assigns priorities based on what triggered the update:

  • User input like typing, clicking, or scrolling gets high priority
  • Updates wrapped in startTransition get low priority

Here’s an example: You’re typing in a search box while React renders a filtered list. When you type, React pauses the list rendering, processes your keystroke immediately, then resumes the list. This keeps typing smooth even during heavy background work.

21. How does the useId hook solve issues with mismatched IDs in server-side rendering?

  • Level: Intermediate
  • Theme: SSR & hooks

This question checks if you understand a common problem in server-side rendering where IDs don’t match between server and client, and how useId fixes it.

How to solve it

useId generates a stable unique ID that stays identical between server and client renders, preventing hydration mismatches. 

Without it, randomly generated IDs differ between server and client, causing React warnings and broken accessibility.

Here’s the problem:

// Wrong - different IDs on server and client

function Form() {

  const id = Math.random().toString();

  return (

    <>

      <label htmlFor={id}>Email</label>

      <input id={id} />

    </>

  );

}

The server generates one random ID, the client generates a different one during hydration. 

Use useId instead:

// Right - consistent IDs

function Form() {

  const id = useId();

  return (

    <>

      <label htmlFor={id}>Email</label>

      <input id={id} />

    </>

  );

}

The ID stays the same across the server and client. Use this for linking form labels to inputs or generating IDs for accessibility attributes in server-rendered apps.

22. Why are React Server Components beneficial, and how do they differ from client components?

  • Level: Intermediate
  • Theme: Server components

This question tests if you understand the difference between server and client components and when to use each.

How to solve it

React Server Components run only on the server and never send their code to the browser, reducing bundle size and improving page load. 

They can fetch data directly, but can’t use state, effects, or event handlers. Client components run in the browser with full React features, including interactivity.

Here’s when to use each:

// Server Component - fetches data on the server

async function UserProfile({ userId }) {

  const user = await db.users.findById(userId);

  return <div>{user.name}</div>;

}

// Client Component - needs interactivity

'use client';

function LikeButton() {

  const [likes, setLikes] = useState(0);

  return <button onClick={() => setLikes(likes + 1)}>{likes}</button>;

}

In a nutshell:

  • Use Server Components for displaying data and static content. 
  • Use Client Components for interactions, state management, and browser APIs. 

Tip: You can use both types together in the same app. A Server Component can include Client Components inside it, so you get the benefits of both—reduced bundle size from server rendering plus interactivity where you need it.

23. What causes hydration mismatches, and how can streaming or selective hydration help?

  • Level: Intermediate
  • Theme: SSR & hydration

This question checks if you understand common server-side rendering problems and modern solutions that improve performance and reliability.

How to solve it

Hydration mismatches happen when the HTML React generates on the server differs from what it generates on the client. 

Common causes include random values, date/time functions, and browser-only APIs that produce different results on server vs client.

Here’s an example that causes problems:

function TimeDisplay() {

  return <div>{new Date().toString()}</div>;

}

The server generates one timestamp, the client generates a different one during hydration. 

React sees different content and throws a warning.

In a nutshell:

  • Streaming hydration solves this by sending HTML to the browser in pieces instead of waiting for everything to finish. The browser can show content faster, and React makes each piece interactive as it arrives. 
  • Selective hydration goes further—if you start interacting with one part of the page, React prioritizes making that part interactive first, even if other parts are still loading. 

Both approaches reduce the chance of mismatches because React can handle timing differences more gracefully.

24. What is the useSyncExternalStore hook, and why was it introduced?

  • Level: Intermediate
  • Theme: External stores & concurrency

This question tests if you understand how React works with external state management libraries in concurrent rendering mode.

How to solve it

useSyncExternalStore lets React components subscribe to external data sources like Redux stores safely.

It makes sure React reads from the store synchronously during render, preventing “tearing”—a visual bug where different parts of your UI show different versions of the same data.

Before concurrent rendering, this wasn’t a problem. React rendered everything in one go, so all components saw the same data. 

With concurrent rendering, React can pause and resume rendering. If the external store updates while React is paused, some components might render with old data and others with new data, creating visual inconsistencies.

Here’s how to use it:

function useStore(store) {

  return useSyncExternalStore(

    store.subscribe,           // Function to subscribe to changes

    store.getSnapshot,         // Function to get current value

    store.getServerSnapshot    // Optional server-side snapshot

  );

}

The hook ensures all components read the same value during a single render, even if the external store updates mid-render.

State management libraries like Redux and Zustand use this hook internally to stay compatible with concurrent features.

25. When would you use useImperativeHandle with forwardRef, and how does it help control child components?

  • Level: Intermediate
  • Theme: Hooks & refs

This question tests if you understand how to expose specific functions from a child component to its parent without giving full access to the component’s internals.

How to solve it

Use useImperativeHandle with forwardRef when a parent needs to call specific methods on a child component—like focusing an input or scrolling to a position—without accessing the child’s internal DOM nodes directly.

This keeps the child’s implementation details hidden while providing a clean, controlled API.

Here’s an example with a custom input:

const CustomInput = forwardRef((props, ref) => {

  const inputRef = useRef();

  useImperativeHandle(ref, () => ({

    focus: () => {

      inputRef.current.focus();

    },

    clear: () => {

      inputRef.current.value = '';

    }

  }));

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

});

// Parent component

function Form() {

  const inputRef = useRef();

  return (

    <>

      <CustomInput ref={inputRef} />

      <button onClick={() => inputRef.current.focus()}>Focus Input</button>

      <button onClick={() => inputRef.current.clear()}>Clear Input</button>

    </>

  );

}

The parent can only call focus() and clear()—methods you explicitly exposed. 

It can’t access the underlying input element or any other internal state. 

Tip: This pattern is useful for building reusable components with controlled APIs, like custom modals that expose open() and close() methods or video players that expose play() and pause().

26. How do you build a flexible wrapper component using props.children, and how can you pass a callback down so the child updates the parent’s state?

  • Level: Intermediate
  • Theme: Composition & state management

This question tests if you understand how to build reusable wrapper components and handle state updates from nested children.

How to solve it

Any elements you nest inside a component’s JSX tags become props.children

Use this to build flexible wrappers that work with any content. To let children update parent state, pass a callback function down as a prop.

Here’s a simple example:

function Card({ children, onSelect }) {

  return (

    <div className="card" onClick={onSelect}>

      {children}

    </div>

  );

}

function Parent() {

  const [selected, setSelected] = useState(null);

  return (

    <Card onSelect={() => setSelected('card1')}>

      <h2>Card Title</h2>

      <p>Card content goes here</p>

    </Card>

  );

}

To sum it up:

  • The Card component doesn’t care what’s inside it—it just renders whatever you pass as children. 
  • The parent keeps the state and passes down onSelect

When the card is clicked, it calls onSelect, which updates the parent’s state.

Tip: This pattern keeps components flexible and reusable. You can use the same Card wrapper with different content throughout your app. The parent controls the state while the child handles the UI and events.

27. What is “prop drilling”, and how can React’s Context API alleviate it?

  • Level: Intermediate
  • Theme: State sharing & context

This question tests if you understand a common React pain point and how to solve it with Context.

How to solve it

Prop drilling happens when you pass props through multiple components that don’t use them, just to reach a deeply nested child. 

React’s Context API lets you share data across the component tree without passing props through every level.

You create a context, provide a value at the top of your tree, and any component below can access that value directly without props being passed through intermediate components.

Without Context:

function App() {

  const [user, setUser] = useState({ name: 'Alice' });

  return <Dashboard user={user} />;

}

function Dashboard({ user }) {

  return <Sidebar user={user} />; // Doesn't use user, just passes it

}

function Sidebar({ user }) {

  return <UserProfile user={user} />; // Doesn't use user, just passes it

}

function UserProfile({ user }) {

  return <div>{user.name}</div>; // Finally uses it

}

With Context:

const UserContext = createContext();

function App() {

  const [user, setUser] = useState({ name: 'Alice' });

  return (

    <UserContext.Provider value={user}>

      <Dashboard />

    </UserContext.Provider>

  );

}

function UserProfile() {

  const user = useContext(UserContext);

  return <div>{user.name}</div>;

}

Here’s what happens:

  • The Provider makes the value available to all components below it. 
  • Dashboard and Sidebar don’t need to know about the user anymore. 
  • UserProfile reads it directly via useContext

Tip: Use Context for data that many components need—like themes, user info, or language settings. Avoid it for data that changes frequently (like form input values) because every component reading from that context will re-render whenever the value updates, which can hurt performance.

28. How do you read and update query parameters in React Router, and what happens when you call setSearchParams?

  • Level: Intermediate
  • Theme: Routing & URL management

This question tests if you know how to work with URL query parameters in React Router—a popular library for handling navigation and routing in React applications.

How to solve it

Use the useSearchParams() hook, which returns the current query parameters and a function to update them. 

  • Reading values uses searchParams.get(‘key’). 
  • Updating with setSearchParams() triggers navigation and changes the URL.
import { useSearchParams } from 'react-router-dom';

function ProductList() {

  const [searchParams, setSearchParams] = useSearchParams();

  const page = searchParams.get('page') || '1';

  const sort = searchParams.get('sort') || 'name';

  const handlePageChange = (newPage) => {

    setSearchParams({ page: newPage, sort });

  };

  return (

    <div>

      <p>Page {page}, sorted by {sort}</p>

      <button onClick={() => handlePageChange(2)}>

        Go to page 2

      </button>

    </div>

  );

}

When you call setSearchParams({ page: 2 }), React Router updates the URL from ?page=1&sort=name to ?page=2&sort=name

This triggers navigation—the component re-renders with the new params. The URL change is reflected in the address bar, so users can bookmark it or share it. 

Tip: You can also pass a callback to setSearchParams to update params based on the current values.

29. What are time slicing and preemption in React’s scheduler, and how do they improve app responsiveness?

  • Level: Advanced
  • Theme: Concurrency & scheduler

This question tests if you understand the mechanics behind React’s concurrent rendering and how it keeps UIs responsive during heavy work.

How to solve it

Time slicing divides rendering work into small chunks. Preemption pauses low-priority work when urgent events occur, handles them immediately, then resumes the paused work. 

Together, they prevent long renders from freezing the UI.

Here’s how it works:

  • Without time slicing, rendering a complex component that takes 500ms locks up the browser—typing lags, clicks don’t register, scrolling stutters. 
  • Time slicing breaks that 500ms into chunks of maybe 5ms each. Between chunks, React checks for urgent events.

Say you’re typing in a search box while React renders a filtered list. 

The typing event has high priority, and the list render has low priority. React pauses the list render partway through, processes your keystroke immediately so the input stays responsive, then goes back to finish rendering the list. 

And here’s what matters: the user experience stays smooth because urgent interactions always take precedence over background work.

30. How can you prevent unnecessary re-renders in deeply nested component trees, and what strategies optimize performance?

  • Level: Advanced
  • Theme: Performance & re-rendering

This question tests your knowledge of React performance optimization techniques for complex applications.

How to solve it

Use React .memo to skip re-renders when props haven’t changed, useMemo to cache expensive calculations, and useCallback to stabilize function references, and split contexts to prevent unnecessary re-renders across your tree. 

For complex state needs, consider libraries like Zustand that offer fine-grained subscriptions.

Wrap components with React.memo:

const ExpensiveChild = React.memo(({ data }) => {

  return <div>{/* complex rendering */}</div>;

});

The component only re-renders when data actually changes, not when the parent re-renders for unrelated reasons.

Cache expensive calculations:

const filteredItems = useMemo(() => 

  items.filter(item => item.active), 

  [items]

);

Without useMemo, the filter runs on every render. With it, React reuses the previous result unless items changes.

This pattern is a form of memoization: React keeps the previous result around and only recomputes when the dependencies change. In a performance-focused answer, you can also mention route-level lazy loading with React.lazy and Suspense, and legacy patterns like a higher-order component (HOC) that wraps another component to add logging, analytics, or caching without touching its internals.

Stabilize callbacks so they don’t trigger child re-renders:

const handleClick = useCallback(() => doSomething(id), [id]);

Without useCallback, you create a new function on every render. Child components receiving this function see it as a “change” and re-render unnecessarily.

Tip: Split large contexts into smaller ones. If you have one context with user data, theme, and settings, components re-render whenever any value changes. Separate contexts mean components only re-render for the data they actually use.

31. How do you measure and diagnose performance bottlenecks in a React application?

  • Level: Advanced
  • Theme: Performance tools

This question tests if you know how to identify and fix performance problems in React apps.

How to solve it

Use React Profiler to find slow components, browser DevTools Performance tab for overall analysis, Lighthouse for user-facing metrics, and why-did-you-render to catch unnecessary re-renders.

  • React Profiler shows you which components are slow. Open React DevTools, click the Profiler tab, record a session while using your app, then review the results. It shows render duration for each component and why it re-rendered. Look for components with long bars or frequent re-renders.
  • Browser DevTools Performance tab gives you the full picture. Record while interacting with your app and check the flame chart. Long yellow blocks mean JavaScript is blocking the main thread. The memory profiler helps find leaks.
  • Lighthouse runs in Chrome DevTools and measures real user experience—First Contentful Paint, Time to Interactive, Total Blocking Time. It provides scores and specific suggestions.
  • Adding why-did-you-render to your dev setup so that it logs components that re-rendered even though their props didn’t change. This catches common optimization mistakes.

Pass your React interview and land a developer role

We’ve explored React interview questions covering beginner to advanced topics. The next step is putting this knowledge into practice.

Mimo’s Front-End Development career path teaches you React along with HTML, CSS, and JavaScript through hands-on projects.

Here’s what you get:

  • Interactive lessons that teach React fundamentals and more advanced concepts
  • 13 GitHub portfolio projects you can show to potential employers
  • Practice with the key patterns and hooks covered in this guide
  • Professional certification recognized globally

Start learning React for free

Henry Ameseder

AUTHOR

Henry Ameseder

Henry is the COO and a co-founder of Mimo. Since joining the team in 2016, he’s been on a mission to make coding accessible to everyone. Passionate about helping aspiring developers, Henry creates valuable content on programming, writes Python scripts, and in his free time, plays guitar.

Learn to code and land your dream job in tech

Start for free