Skip to content

React Frontend Developer Interview Questions & Answers

40 questions for React Frontend Developer interviews — 24 easy, 15 medium, 1 hard.

About the React Frontend Developer role

A React Frontend Developer focuses on the user interface: building reusable components, managing state, fetching data and making pages fast and accessible. You work closely with designers and backend developers, convert Figma screens into responsive layouts, and own performance, testing and browser issues. Strong JavaScript fundamentals, hooks and state management knowledge are essential, and many MERN developers start or specialise here.

JavaScript ES6+ React hooks State management Responsive CSS Testing Library
Solved for this roleStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

What is React and how does the virtual DOM help performance?

Save to ▾
Show answer
React is a JavaScript library for building user interfaces from reusable components. When state changes, React re-renders components into a lightweight in-memory tree called the virtual DOM, compares it with the previous tree through reconciliation, and applies only the minimal changes to the real DOM. Direct DOM updates are expensive, so batching and diffing keep updates efficient while letting developers write declarative code.
02

What are the common ways to render content conditionally in React?

Save to ▾
Show answer
Use an early return for whole-component cases like loading, an if statement outside JSX, the ternary operator for either-or markup, and logical && for show-or-hide. Be careful with && on numbers: count && <Badge /> renders 0 when count is zero, so use count > 0 && <Badge />. For many states, map a status value to components with an object lookup.
03

Explain hoisting in JavaScript with an example.

Save to ▾
Show answer
Hoisting means declarations are processed before code runs. Function declarations are hoisted fully, so you can call them before they appear. var declarations are hoisted but initialised to undefined, so console.log(x) before var x = 5 prints undefined. let, const and class declarations are hoisted too, but accessing them before the declaration throws a ReferenceError because of the temporal dead zone. Function expressions assigned to variables follow the variable rules.
04

Why are functional components preferred over class components today?

Save to ▾
Show answer
Functional components with hooks need less code, avoid confusion around this binding, and let you reuse stateful logic through custom hooks instead of higher-order components or render props. All new React features, such as Server Components and hooks like useActionState, target functions. Class components still work and appear in older codebases, and error boundaries still require a class or a library wrapper.
05

Write Express middleware that logs method, URL, status code and response time.

Save to ▾
Show answer
Hook into the response finish event to know the final status. function requestLogger(req, res, next) { const start = process.hrtime.bigint(); res.on('finish', () => { const ms = Number(process.hrtime.bigint() - start) / 1e6; console.log(`${req.method} ${req.originalUrl} ${res.statusCode} ${ms.toFixed(1)}ms`); }); next(); } app.use(requestLogger); In production, use a structured logger like pino instead of console.log.
06

What is a closure and where is it useful?

Save to ▾
Show answer
A closure is a function that remembers the variables of the scope where it was created, even after that outer function has returned. For example, a makeCounter function can return an inner function that increments a private count variable. Closures power data privacy, function factories, memoization, debounce and throttle helpers, and React hooks, where event handlers capture props and state from the render that created them.
07

Write a controlled login form that submits to an API.

Save to ▾
Show answer
One state object and a shared change handler. function LoginForm() { const [form, setForm] = useState({ email: '', password: '' }); const onChange = (e) => setForm({ ...form, [e.target.name]: e.target.value }); const onSubmit = async (e) => { e.preventDefault(); const res = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(form) }); if (!res.ok) alert('Invalid credentials'); }; return ( <form onSubmit={onSubmit}> <input name='email' value={form.email} onChange={onChange} /> <input name='password' type='password' value={form.password} onChange={onChange} /> <button>Login</button> </form> ); }
08

Two sibling components need to share data. How do you handle it?

Save to ▾
Show answer
Lift the shared state to their nearest common parent and pass the value to one sibling and an updater to the other. If the data is needed by many components deep in the tree, use Context or a state library like Zustand or Redux Toolkit. If the data comes from the server, a data-fetching library like TanStack Query can share the cached result across components.
09

Write a counter component using useState.

Save to ▾
Show answer
Use the functional updater when the new value depends on the old one. import { useState } from 'react'; export default function Counter() { const [count, setCount] = useState(0); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount((c) => c + 1)}>+</button> <button onClick={() => setCount((c) => c - 1)}>-</button> <button onClick={() => setCount(0)}>Reset</button> </div> ); }
10

Implement a shopping cart with useReducer.

Save to ▾
Show answer
A pure reducer keeps cart logic in one place. function cartReducer(state, action) { switch (action.type) { case 'add': { const found = state.find((i) => i.id === action.item.id); return found ? state.map((i) => i.id === action.item.id ? { ...i, qty: i.qty + 1 } : i) : [...state, { ...action.item, qty: 1 }]; } case 'remove': return state.filter((i) => i.id !== action.id); case 'clear': return []; default: return state; } } const [cart, dispatch] = useReducer(cartReducer, []); dispatch({ type: 'add', item: product });
11

How does prototypal inheritance work, and how does class syntax relate to it?

Save to ▾
Show answer
Every object has an internal link to a prototype object. When a property is missing, JavaScript walks this prototype chain until it finds it or reaches null. Class syntax is mostly sugar over this model: methods defined in a class live on Constructor.prototype, and extends sets up the chain between prototypes. Classes add stricter behaviour, such as requiring new and supporting private fields with the # prefix.
12

A for loop using var with setTimeout inside prints 3, 3, 3 instead of 0, 1, 2. Why, and how do you fix it?

Save to ▾
Show answer
var is function-scoped, so all three callbacks close over the same variable, which has become 3 by the time the timers fire. The simplest fix is to declare the loop variable with let, because let creates a fresh binding for every iteration. Older fixes include wrapping the body in an immediately invoked function or passing i as the third argument to setTimeout.
13

How should passwords be stored, and why use bcrypt?

Save to ▾
Show answer
Never store plain or reversibly encrypted passwords. Store a slow, salted hash. bcrypt generates a random salt per password, so identical passwords produce different hashes and rainbow tables fail, and its cost factor, typically 10 to 12, makes brute force expensive. At login use bcrypt.compare. Argon2id is a modern alternative. Fast hashes like MD5 or SHA-256 alone are unsuitable for passwords.
14

What are the main uses of useRef?

Save to ▾
Show answer
useRef returns a mutable object whose current property persists across renders without causing a re-render when changed. It is used to access DOM nodes, for example focusing an input or measuring size, and to store values like timer ids, previous values or the latest callback. Do not read or write ref.current during rendering for values that affect output, because React will not re-render when it changes.
15

What is a Promise and what are its states?

Save to ▾
Show answer
A Promise represents the eventual result of an asynchronous operation. It starts in the pending state and settles once, either fulfilled with a value or rejected with a reason, and never changes after that. You consume it with then, catch and finally, or with await inside an async function. Promises replaced deeply nested callbacks in Node.js APIs and make error propagation through a chain much easier.
16

Tell me about a time you received critical feedback on your UI code and how you responded.

Save to ▾
Show answer
Situation: in my internship, a senior reviewer rejected my pull request because my components were large and repeated logic. Task: fix it without missing the sprint deadline. Action: I asked for examples, split the page into smaller components, extracted a custom hook for the shared fetching logic and added prop types. Result: the PR was approved the next day, and the reviewer used my hook in another feature.
17

What is the difference between var, let and const in JavaScript?

Save to ▾
Show answer
var is function-scoped, hoisted with the value undefined and can be redeclared. let and const are block-scoped and sit in the temporal dead zone until their declaration line runs. const blocks reassignment of the binding, but an object or array declared with const can still be mutated. In modern MERN code use const by default, let when the value must change, and avoid var.
18

Why does React need keys in lists, and why is using the array index risky?

Save to ▾
Show answer
Keys tell React which list item is which between renders, so it can reuse, move or remove the correct DOM nodes and component state. Use stable unique ids, such as a MongoDB _id. Index keys break when items are inserted, removed or reordered: state such as input text or checkbox values can attach to the wrong item, and rendering becomes less efficient. Indexes are acceptable only for static lists.
19

Walk me through a MERN project you built, end to end.

Save to ▾
Show answer
Situation: I built a job portal as my major project. Task: let recruiters post jobs and students apply with resumes. Action: I designed MongoDB collections for users, jobs and applications with indexes, built an Express REST API with JWT auth and role checks, a React frontend with React Router and TanStack Query, uploaded resumes to cloud storage, wrote API tests and deployed with Docker. Result: 60 classmates used it during placement season.
20

How does async/await improve on Promise chains, and how do you handle errors with it?

Save to ▾
Show answer
async/await is syntax over Promises that lets asynchronous code read top to bottom like synchronous code. An async function always returns a Promise, and await pauses that function until the Promise settles. Errors are handled with try/catch/finally instead of chained catch calls. A common mistake is awaiting independent calls one after another; use Promise.all to run them in parallel when they do not depend on each other.
21

What is the difference between props and state in React?

Save to ▾
Show answer
Props are inputs passed from a parent to a child component; they are read-only inside the child. State is data owned and managed by a component itself, created with useState or useReducer, and changing it triggers a re-render. A common pattern is that a parent keeps state and passes both the value and a setter function down as props to children.
22

Group an array of order objects by their status using reduce.

Save to ▾
Show answer
reduce builds an object whose keys are statuses and values are arrays. const grouped = orders.reduce((acc, order) => { (acc[order.status] ||= []).push(order); return acc; }, {}); // { paid: [...], pending: [...] } Newer runtimes also offer Object.groupBy(orders, (o) => o.status), which returns the same shape with a null prototype.
23

What is JSX and how is it converted into JavaScript?

Save to ▾
Show answer
JSX is a syntax extension that lets you write HTML-like markup inside JavaScript. A compiler such as Babel, esbuild or SWC, used by Vite, turns each element into a function call that creates a React element object. JSX supports JavaScript expressions inside curly braces, uses className instead of class and htmlFor instead of for, and requires one parent element or a fragment.
24

How should a component display data loaded from an API in a user-friendly way?

Save to ▾
Show answer
Handle every state explicitly: show a skeleton or spinner while loading, an error message with a retry button if the request fails, an empty state with guidance when there is no data, and the content otherwise. Keep these in state variables or use a library like TanStack Query that provides isPending, isError and data. Never leave a blank screen or crash on undefined data.
25

How do class component lifecycle methods map to hooks?

Save to ▾
Show answer
componentDidMount maps to useEffect with an empty dependency array. componentDidUpdate maps to useEffect with specific dependencies. componentWillUnmount maps to the cleanup function returned from useEffect. shouldComponentUpdate is roughly React.memo, and getDerivedStateFromProps is usually replaced by computing values during render. The mindset shifts from lifecycle moments to synchronising with external systems whenever certain values change.
26

You are building a registration form with ten fields and validation. How do you manage its state?

Save to ▾
Show answer
For a simple form, keep a single state object and update fields with a shared handler using the input name, for example setForm({ ...form, [e.target.name]: e.target.value }). Validate on blur and submit, storing errors in another object. For larger forms, use React Hook Form with a zod schema, which reduces re-renders and shares the validation schema with the Express backend.
27

How does the useEffect dependency array work and why is cleanup important?

Save to ▾
Show answer
useEffect runs after render. With no array it runs after every render, with an empty array only after mount, and with dependencies whenever any of them change by Object.is comparison. The function you return is the cleanup, which runs before the next effect and on unmount. Use it to remove listeners, clear intervals, abort requests and close sockets, otherwise you get leaks and duplicate subscriptions.
28

Why do you want to work as a MERN stack developer?

Save to ▾
Show answer
I enjoy building complete products, and MERN lets me use one language, JavaScript, across the database queries, the API and the user interface. In my projects, such as a job portal with React, Express and MongoDB, I liked seeing a feature go from schema to screen. The stack is widely used by startups and service companies in India, and I want to grow into a full stack engineer who owns features end to end.
29

What is Express.js and what is middleware?

Save to ▾
Show answer
Express is a minimal web framework for Node.js that adds routing, middleware and helpers on top of the http module. Middleware is a function with the signature (req, res, next) that runs during the request cycle. It can read or modify the request, end the response, or call next() to pass control on. Body parsing, logging, authentication, CORS and error handling are all built as middleware.
30

How do arrow functions differ from regular functions?

Save to ▾
Show answer
Arrow functions have a shorter syntax and do not have their own this, arguments, super or new.target; they take this from the surrounding lexical scope. They cannot be used as constructors with new. This makes them ideal for callbacks, array methods and React event handlers. They are a poor choice for object methods that need this to refer to the object, or for prototype methods.
31

A search box fires an API request on every keystroke and overloads the backend. How would you solve it?

Save to ▾
Show answer
Debounce the input so the request goes out only after the user stops typing for around 300 ms. Also skip very short queries, cancel the previous request with AbortController so stale responses cannot overwrite newer ones, and cache recent results. On the server side, add rate limiting and an index on the searched field. Throttling is the alternative when you need periodic updates, like scroll tracking.
32

Build a simple todo list in React with add and delete.

Save to ▾
Show answer
Update arrays immutably. function Todos() { const [todos, setTodos] = useState([]); const [text, setText] = useState(''); const add = (e) => { e.preventDefault(); if (!text.trim()) return; setTodos((t) => [...t, { id: crypto.randomUUID(), text }]); setText(''); }; const remove = (id) => setTodos((t) => t.filter((x) => x.id !== id)); return ( <form onSubmit={add}> <input value={text} onChange={(e) => setText(e.target.value)} /> <ul>{todos.map((t) => ( <li key={t.id}>{t.text} <button type='button' onClick={() => remove(t.id)}>x</button></li> ))}</ul> </form> ); }
33

Tell me about a time you had to learn a new JavaScript concept quickly to finish a task.

Save to ▾
Show answer
Situation: in my final-year project our dashboard froze while loading data from three APIs. Task: I had to fix it before the demo in two days. Action: I studied Promises and async/await properly, rewrote the nested callbacks, and used Promise.all to load the APIs in parallel with proper error handling. Result: load time dropped from 6 seconds to under 2, and I documented the pattern for my team.
34

Write a debounce function in JavaScript.

Save to ▾
Show answer
Debounce delays a call until a quiet period has passed. Each new call clears the previous timer. function debounce(fn, delay = 300) { let timer; return function (...args) { clearTimeout(timer); timer = setTimeout(() => fn.apply(this, args), delay); }; } const onSearch = debounce((q) => fetchResults(q), 400); It relies on a closure over timer and keeps this and arguments intact.
35

An error in one dashboard widget crashes the entire React page. How do you contain it?

Save to ▾
Show answer
Wrap risky sections in error boundaries. An error boundary catches rendering errors in its subtree and shows fallback UI instead of unmounting the whole app. React still requires a class with getDerivedStateFromError and componentDidCatch, or you can use the react-error-boundary package. Place boundaries around each widget and the route level, log errors to monitoring, and offer a retry. They do not catch errors in event handlers or async code.
36

What is the difference between == and === in JavaScript?

Save to ▾
Show answer
== compares values after type coercion, so 0 == '0' and null == undefined are both true. === compares value and type without coercion, so 0 === '0' is false. Coercion rules are hard to remember and cause subtle bugs, so teams use === everywhere, often enforced by an ESLint rule. A common accepted exception is value == null, which checks for both null and undefined in one step.
37

Explain destructuring, the spread operator and rest parameters.

Save to ▾
Show answer
Destructuring unpacks values from arrays or objects into variables, for example const { name, email } = user, with optional defaults and renaming. Spread (...) expands an iterable or object, used to copy arrays, merge objects or pass arguments. Rest uses the same syntax to collect remaining items, as in function sum(...nums) or const { password, ...safeUser } = user. In React, spread is used constantly to create new state objects immutably.
38

A component calls setState inside useEffect and the app goes into an infinite render loop. Why?

Save to ▾
Show answer
The effect updates state, which re-renders, which runs the effect again. This happens when the dependency array is missing, or when a dependency is a new object or array created every render, or when the effect sets the same state it depends on. Add correct dependencies, move object creation inside the effect or memoize it, and ask whether the value can be calculated during render instead.
39

Write a function to flatten a nested array without using Array.prototype.flat.

Save to ▾
Show answer
Recursion with reduce is the cleanest approach. function flatten(arr) { return arr.reduce((acc, item) => Array.isArray(item) ? acc.concat(flatten(item)) : acc.concat(item), []); } flatten([1, [2, [3, [4]]], 5]); // [1, 2, 3, 4, 5] For very deep arrays, an iterative version with an explicit stack avoids hitting the recursion limit.
40

When should you use useReducer instead of useState?

Save to ▾
Show answer
Use useReducer when state has multiple related fields, when the next state depends on complex logic, or when many event handlers update state in different ways. A reducer is a pure function (state, action) => newState that centralises transitions and is easy to unit test, for example a cart with add, remove, change quantity and clear actions. For simple independent values, useState is clearer.

Frequently asked questions

What does a React Frontend Developer do?

A React Frontend Developer focuses on the user interface: building reusable components, managing state, fetching data and making pages fast and accessible. You work closely with designers and backend developers, convert Figma screens into responsive layouts, and own performance, testing and browser issues. Strong JavaScript fundamentals, hooks and state management knowledge are essential, and many MERN developers start or specialise here.

Which skills are tested in a React Frontend Developer interview?

Expect questions on JavaScript ES6+, React hooks, State management, Responsive CSS, Testing Library. Most rounds also ask you to explain a project and solve one practical problem live.

How do I prepare for a React Frontend Developer interview?

Revise Modern JavaScript (ES6+), React Fundamentals, React Hooks, State and Performance first using the topic sheets, practise the questions on this page aloud, then do one full mock interview to practise timing.