Getting ready for a React JS interview? It can feel overwhelming, especially if you’re not sure where to start. React’s still the go-to for front-end work, so knowing its core ideas is a must for anyone serious about building modern web apps.
I have given 75 React JS interview questions and answers to help you sharpen your skills and walk into interviews with way more confidence.
Each section digs into core ideas like React hooks, component lifecycle, state management, and performance tips. The goal? Make advanced concepts less intimidating and help you feel more at home with both the basics and the trickier stuff.
1. What is React, and why use it?
React is a JavaScript library for building user interfaces. It’s all about creating reusable components that decide how data shows up on the screen.

Meta (yep, Facebook) built it to help developers make single-page apps that feel fast and smooth. React makes UI development way less painful, thanks to its declarative style and the virtual DOM.
Instead of updating the whole page, React only changes what’s necessary. That’s a big deal for performance.
React also offers handy features like state management and hooks, which make dynamic behavior a breeze. For example:
function Welcome() {
const [name, setName] = React.useState("User");
return <h1>Hello, {name}!</h1>;
}That component updates instantly when the data changes. You can see how React keeps interactive content snappy.
2. Explain the virtual DOM in React.
The Virtual DOM is React’s way of managing UI changes without hammering the real DOM every time. Instead of tweaking the actual DOM with every update, React updates an in-memory version first.

When a component’s state or props change, React builds a new Virtual DOM tree. Then it compares that to the previous one—a process called reconciliation.
This lets React figure out exactly what’s different. It updates just those parts in the real DOM, which keeps things quick.
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);Here, only the button’s text changes when you click. No unnecessary re-renders.
3. Describe the component lifecycle in React.
React components move through three main phases: mounting, updating, and unmounting. Each phase marks a different point in a component’s life—from creation to removal.
Class components use lifecycle methods to control what happens at each stage. For example, componentDidMount() runs after the component appears, and componentWillUnmount() fires right before it disappears.
Functional components use hooks like useEffect() for similar jobs. The effect hook can run after rendering and clean up when the component unmounts.
useEffect(() => {
console.log('Mounted');
return () => console.log('Unmounted');
}, []);4. What are React Hooks?
React Hooks are built-in functions that let you use state and lifecycle features in functional components. They showed up in React 16.8 and made most class components kind of obsolete.
Hooks let you manage state, run side effects, and tap into context—all with less fuss. The most common ones? useState, useEffect, and useContext.
With useState, you can update state like this:
const [count, setCount] = useState(0);You get a state variable (count) and a function to update it (setCount). Hooks keep logic reusable and components easier to read, since you skip the class syntax.
5. How does useState work in React?
The useState hook lets you manage state in functional components—no classes needed. It gives you a pair: the current value and a function to update it.

When you call useState, you create a piece of state that’s independent from others. You can store numbers, strings, arrays, objects—whatever you need. Usually, you’ll give it a default value right away.
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return <button onClick={handleClick}>Clicked {count} times</button>;
}Clicking the button updates the state, and React re-renders the component with the new count. It just works.
6. Explain useEffect hook with an example.
The useEffect Hook handles side effects—stuff like fetching data, changing the document title, or setting up subscriptions. It runs after the component renders and can re-run when its dependencies change.
It takes a callback and an optional array of dependencies. If you pass an empty array, it runs only once after the first render (just like componentDidMount in class components).
import { useEffect, useState } from "react";
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Clicked ${count} times`;
}, [count]);
return <button onClick={() => setCount(count + 1)}>Click {count}</button>;
}Here, the effect updates the document title every time count changes.
7. What is JSX?
JSX stands for JavaScript XML. It’s a syntax extension that lets you write HTML-like code right inside JavaScript. JSX makes it way easier to see what your UI will look like.
Browsers don’t understand JSX by default, so tools like Babel compile it down to regular JavaScript. For instance, this:
const element = <h1>Hello, React!</h1>;
turns into:
const element = React.createElement('h1', null, 'Hello, React!');JSX lets you embed expressions, pass attributes, and use JavaScript logic inside your markup. That consistency makes components a lot easier to build and maintain.
8. Difference between functional and class components
Functional components use regular JavaScript functions. They take props as input and spit out JSX for the UI.
With Hooks, functional components can now handle state, effects, and more—stuff that used to require class components.
Class components rely on ES6 classes that extend React.Component. They use this.state for state and methods like componentDidMount for lifecycle events.
Functional components are generally easier to write, test, and read. They also tend to be a bit lighter on memory. Class components still matter for older codebases, though.
// Functional Component
function Greeting({ name }) {
return <h1>Hello, {name}</h1>;
}
// Class Component
class Greeting extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}9. How to handle events in React?
Event handling in React works a lot like regular JavaScript, but you use JSX-style syntax. That means camelCase for event names—like onClick or onChange—instead of lowercase.
React uses something called SyntheticEvent, which smooths out event behavior across browsers. It’s a little behind the scenes, but you get more consistent results.
You usually define a function and pass it to an element’s event attribute. Like this:
function Button() {
function handleClick() {
alert('Button clicked!');
}
return <button onClick={handleClick}>Click Me</button>;
}If you need to pass arguments, just use an arrow function:
<button onClick={() => handleClick(id)}>Select</button>This style keeps things simple and skips extra binding headaches.
10. Explain React props and state.
Props and state are how React components handle data and updates. Props (short for “properties”) let components get input from their parent, making them reusable with different values.
State is local data that can change over time, like form inputs or toggles. When state updates, React re-renders the component to show the new info.
Props are read-only, while state can change. Most apps use both together for interactive UIs. For example:
function Greeting({ name }) {
const [count, setCount] = useState(0);
return (
<div>
<p>Hello, {name}!</p>
<button onClick={() => setCount(count + 1)}>Clicked {count} times</button>
</div>
);
}11. What is the purpose of keys in lists?
Keys in React help the framework figure out which list items changed, got added, or were removed. They give each element a stable identity, so updates are smoother and less buggy.
Usually, you’ll use something unique like an ID for each key. If you use array indexes as keys and the list changes order, you might run into weird bugs.
const items = ['Apple', 'Orange', 'Banana'];
const list = items.map(item => <li key={item}>{item}</li>);Here, each list item gets a unique key from its name. That way, React keeps everything in sync when the list updates.
12. How do you optimize React app performance?
If you want a faster React app, start by cutting down on unnecessary component re-renders. Use React.memo, useCallback, and useMemo to make sure functions or values don’t get recreated on every render.
These tools let React skip rendering UI parts that haven’t changed. It’s not magic, but it helps.
Handling big lists efficiently matters too. Libraries like React Window or React Virtualized only render what’s visible, so you save time and memory.
Code splitting and lazy loading are also great for speed. With React.lazy and Suspense, components load only when you need them, which shrinks the initial bundle.
const LazyComponent = React.lazy(() => import('./LazyComponent'));Cache API responses and shrink image sizes when possible. Your app will feel smoother, and users will thank you (even if they don’t say it out loud).
13. Describe Context API in React
The Context API lets you share data between React components without having to pass props down every level. It’s a cleaner way to manage global stuff like user info, themes, or language preferences.
Create a context using React.createContext() and wrap the relevant parts of your app in a provider. Any nested component can then access that data as a consumer.
const UserContext = React.createContext();
function App() {
return (
<UserContext.Provider value={{ name: "John" }}>
<Profile />
</UserContext.Provider>
);
}Context API helps you avoid “prop drilling” and keeps components tidier. But if your app gets big and state management turns hairy, you might want to bring in Redux or Zustand for extra muscle.
14. What are higher-order components (HOC)?
A Higher-Order Component (HOC) is basically a function that takes a component and spits out a new one. It’s a way to share logic across components without touching their original code.
HOCs wrap other components to add features, props, or data. They’re handy for things like authentication or logging.
Here’s a simple example:
function withLogger(WrappedComponent) {
return function EnhancedComponent(props) {
console.log('Component rendered with props:', props);
return <WrappedComponent {...props} />;
};
}They’re especially useful in older React projects. Hooks cover a lot of the same ground now, but some libraries and legacy code still lean on HOCs.
15. Explain React Router and its use.
React Router is the go-to library for navigation in React apps. It lets you set up different routes so users can jump between pages without the browser reloading.
This makes single-page apps (SPAs) feel quick and seamless. The library maps URLs to components, so each route shows a unique view.
Usually, you’ll use BrowserRouter, Routes, and Route to lay out your paths. Here’s a basic setup:
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./Home";
import About from "./About";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
}This code switches components based on the current URL path. Pretty straightforward, right?
16. How to pass data between components?
Props are the main way to pass data from a parent to a child component in React. It’s simple and direct. For example:
function Child({ message }) {
return <p>{message}</p>;
}
function Parent() {
return <Child message="Hello from parent" />;
}Props are read-only, so kids can’t change what the parent sends down. If you need siblings or cousins to share or update the same data, just “lift state up” to their nearest shared parent.
For bigger apps or when data needs to go deep, use tools like Context API, Redux, or other state libraries. That way, you avoid endless prop passing and keep things sane.
17. What are controlled components?
Controlled components are input elements whose values are managed by React state. Instead of keeping their own data, they get it from props and update via events.
Every change in the input fires an event, which updates the state. This keeps the UI and your data in sync.
It gives you full control over form behavior. You can validate, disable, or give feedback as users type. React becomes the single source of truth for what’s in the input.
Here’s how it looks in action:
function NameInput() {
const [name, setName] = React.useState("");
return (
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
);
}The name state holds the value, and changes update it instantly. It’s simple, but super effective.
18. What is reconciliation in React?
Reconciliation is React’s way of updating the UI when your data changes. React compares the new Virtual DOM with the old one to figure out what actually changed.
It then updates just those parts of the real DOM. That keeps things fast and efficient.
The diffing algorithm is key here—it finds out which elements to create, update, or remove. When rendering lists, always give items a unique key prop, so React can track them properly.
{items.map(item => (
<li key={item.id}>{item.name}</li>
))}If you skip proper keys, React might mess up and re-render things it shouldn’t. That leads to glitches or weird updates in your UI.
19. Explain the difference between state and props.
State and props both deal with data in React, but they’re not the same. State is internal—each component manages its own state, and it changes over time (like after a button click).
Props are external. A parent passes them down to a child, making components reusable with different data each time.
State is mutable. You update it with setState or useState. Props are immutable from the child’s perspective—you can’t change what you get from above.
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}Here, name is a prop from the parent. If you use useState inside the component, that’s your state.
20. What are pure components?
Pure components only re-render when their props or state change. This helps your app run faster by dodging unnecessary updates.
React uses a shallow comparison to check if anything’s different before re-rendering. You can make a pure component by extending React.PureComponent for classes or using React.memo for functions.
import React from 'react';
const UserCard = React.memo(function UserCard({ name }) {
return <h3>{name}</h3>;
});They work best when your props and state are simple and immutable. If you mutate objects or arrays, React might miss changes and skip updates you actually need. So, be careful with how you handle your data.
21. How to manage forms in React?
React handles forms by tying input values to state and updating them on every change. Controlled components are the standard way—React state holds the data, and the UI always matches it.
Uncontrolled components are an option too. They use the DOM to store data and get values with refs. It’s simpler, but you lose some predictability.
For big forms or tricky validation, reach for Context API or libraries like Formik or React Hook Form. They help keep your code organized and avoid repeating yourself.
Here’s a controlled form example:
function MyForm() {
const [name, setName] = useState('');
return (
<form>
<input value={name} onChange={(e) => setName(e.target.value)} />
</form>
);
}22. What is React Fiber?
React Fiber is the engine under the hood that handles UI updates. It showed up in React 16, swapping out the old reconciliation for something more flexible and efficient.
Fiber splits rendering into tiny units called “fibers.” That way, React can pause, resume, or cancel work as needed. Your UI stays snappy, even during heavy tasks.
It also brings prioritization and better support for animations and gestures. Fiber helps React juggle multiple updates without freezing the main thread.
// Example: a React component still uses setState normally
this.setState({ count: this.state.count + 1 });
// Fiber internally handles how and when this update is applied23. Explain Error Boundaries in React
Error Boundaries are special components that catch JavaScript errors in their child components. They stop your whole app from crashing when something goes wrong.
They use lifecycle methods like componentDidCatch(error, info) or static getDerivedStateFromError() to log errors and show a fallback UI instead of a broken tree.
Usually, you make Error Boundaries as class components. Here’s a basic example:
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
console.error(error, info);
}
render() {
return this.state.hasError ? <h2>Something went wrong.</h2> : this.props.children;
}
}24. What are React fragments?
React fragments let you group multiple elements without adding extra nodes to the DOM. This keeps your DOM cleaner and avoids unnecessary <div> wrappers.
They’re like invisible containers. Instead of wrapping children in a real element, fragments let you return multiple elements from a component.
You can use the long form <React.Fragment> or short syntax <> and </>.
function Example() {
return (
<>
<h1>Title</h1>
<p>Some text.</p>
</>
);
}Fragments can also take keys when you’re mapping lists, so you can render collections without cluttering up the DOM with extra elements.
25. How to perform conditional rendering?
Conditional rendering in React means you only show components or elements when certain conditions are true. It lets you control what users see based on the app’s state or whatever data you’ve got at the moment.
Most developers use classic JavaScript tricks like if statements, ternary operators, or even logical && for this.
{isLoggedIn ? <Dashboard /> : <Login />}Early returns inside functions work too, so you can skip rendering when some condition fails:
if (!items.length) {
return <p>No items found.</p>;
}
return <ItemList items={items} />;26. Explain the role of Redux with React.
Redux helps React apps manage state in a predictable and centralized way. All shared data lives in a single object called the store, so you can always trace how data changes over time.
This is a lifesaver in big apps where state can get messy fast.
React components access the store through React-Redux, which connects them to specific parts of the state. If a component needs to update data, it dispatches an action describing the change.
Reducers handle these actions and update the store as needed.
import { useSelector, useDispatch } from "react-redux";
import { increment } from "./counterSlice";
function Counter() {
const count = useSelector((state) => state.counter.value);
const dispatch = useDispatch();
return <button onClick={() => dispatch(increment())}>{count}</button>;
}27. What are synthetic events?
Synthetic events in React are wrappers around the browser’s native events. They give you a consistent interface that works the same way across all browsers, so you can skip a lot of the browser-specific headaches.
React manages its internal event system using these synthetic events and boosts performance by delegating events. Instead of attaching handlers to every element, React puts them on a single root element and tracks things from there.
A synthetic event has the same properties and methods as the native event—stuff like stopPropagation() and preventDefault(). You can handle clicks, key presses, and the usual suspects predictably.
function Button() {
function handleClick(e) {
e.preventDefault();
console.log('Synthetic event handled');
}
return <button onClick={handleClick}>Click Me</button>;
}28. Difference between useMemo and useCallback
The useMemo and useCallback hooks both help optimize React component performance. They control when values or functions get re-created during re-renders, which can prevent unnecessary updates.
useMemo returns a memoized value. It runs a function and stores the result, so React can skip recalculating unless one of its dependencies changes. This comes in handy for heavy computations.
const memoizedValue = useMemo(() => computeValue(a, b), [a, b]);useCallback returns a memoized function. It keeps the same function reference between renders unless its dependencies change, which is useful when passing callbacks to child components.
const memoizedCallback = useCallback(() => handleClick(id), [id]);29. Explain lazy loading in React.
Lazy loading in React delays loading a component until you actually need it. This cuts down the size of your initial JavaScript bundle and can really speed up the first load, especially for big components or pages users might not visit right away.
Most folks use React.lazy() and Suspense for this. React.lazy() lets you import a component dynamically, and Suspense shows a fallback UI while the component loads.
const UserProfile = React.lazy(() => import('./UserProfile'));
function App() {
return (
<React.Suspense fallback={<div>Loading...</div>}>
<UserProfile />
</React.Suspense>
);
}30. How does React handle forms?
React manages forms by tying input values directly to component state. Each form element links its value to state, creating what’s called a controlled component. That way, React controls all the data flow in the form.
When you type in a field, an onChange event updates the state. The new state value then updates the input field, keeping everything in sync.
function ContactForm() {
const [name, setName] = React.useState("");
const handleChange = (e) => setName(e.target.value);
return (
<form>
<input type="text" value={name} onChange={handleChange} />
</form>
);
}Uncontrolled components do the opposite—they rely on the DOM to store input values and use refs to access data. It’s simpler, but you lose some control.
31. Describe portals in React.
Portals in React let you render components outside their parent DOM hierarchy, but still keep the React data flow intact. They’re perfect for stuff like modals, alerts, or tooltips that need to float above everything else.
React gives you createPortal for this. You pass it the JSX you want to render and the target DOM node.
import ReactDOM from 'react-dom';
ReactDOM.createPortal(
<div className="modal">This is a modal</div>,
document.getElementById('modal-root')
);Even if the element shows up somewhere else in the DOM, it still acts as part of the same React component tree. Events like clicks or key presses bubble up as you’d expect, so component behavior stays predictable.
32. What are refs and how to use them?
Refs in React give you a way to directly access or interact with DOM elements or React components. They’re handy when you need to handle focus, measure the size of an element, or call methods on child components—basically, whenever you can’t do it with props or state alone.
In functional components, you create refs with the useRef() hook:
import { useRef } from "react";
function InputFocus() {
const inputRef = useRef(null);
function handleFocus() {
inputRef.current.focus();
}
return (
<>
<input ref={inputRef} type="text" />
<button onClick={handleFocus}>Focus Input</button>
</>
);
}In class components, you use React.createRef() and attach it with the ref attribute. Use refs sparingly—only when you really need direct DOM access.
33. Explain server-side rendering (SSR) in React.
Server-side rendering (SSR) means the server generates your React app’s HTML before sending it to the browser. The user sees a fully rendered page right away, instead of waiting for all the JavaScript to load and run.
SSR helps with SEO and can make the first page load feel much faster. Search engines can index pre-rendered HTML, and users get content on their screen with less delay.
In React, SSR works by using ReactDOMServer.renderToString() or renderToPipeableStream() to generate HTML from your components on the server. That HTML is sent to the browser, and React “hydrates” the page—attaching event handlers and making it interactive.
import ReactDOMServer from 'react-dom/server';
const html = ReactDOMServer.renderToString(<App />);34. What is PropTypes and why use it?
PropTypes in React help you check the types of props passed to components during development. Think of them as built-in validation—they warn you if a component gets the wrong type of prop. This makes debugging easier and helps keep communication between components clear.
PropTypes can also improve code readability. Teams can see what kind of data a component expects, which is great in bigger projects where lots of people touch the code.
PropTypes are defined after the component declaration.
MyComponent.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
};In this example, name must be a string and is required, while age is optional and must be a number. TypeScript does compile-time checking, but PropTypes still help with runtime validation.
35. How to debug React applications?
To debug React apps, developers inspect component hierarchies and state changes in real time. The React Developer Tools browser extension lets you view props, state, and rendered components right in your browser.
It’s common to use console.log() to track variable values or see where things go wrong. Browser dev tools let you set breakpoints and pause code to check what’s happening under the hood.
For trickier bugs, error boundaries can catch rendering errors inside components:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error, info) {
this.setState({ hasError: true });
console.error(error, info);
}
render() {
return this.state.hasError ? <p>Error occurred.</p> : this.props.children;
}
}36. Explain the significance of keys in React lists.
Keys in React lists help React figure out which items changed, got added, or were removed. They’re unique identifiers for list elements you create when mapping data to components. If you don’t use proper keys, React can mess up updates and cause weird UI bugs or unnecessary re-renders.
When React compares the current and previous lists, it uses keys to match elements efficiently. A stable, unique key helps rendering performance and keeps component state steady during updates or reordering.
Using array indexes as keys isn’t a great idea if your list order might change.
Here’s a typical example using an id as a key:
{users.map(user => (
<UserCard key={user.id} data={user} />
))}37. What are side effects in React?
In React, side effects are things that happen outside the normal process of rendering the UI. This includes fetching data, updating the DOM directly, or setting up subscriptions—basically, anything that touches the outside world or affects other parts of the app.
React uses the useEffect Hook for side effects in functional components. It runs after rendering and lets you perform actions that aren’t just about returning JSX.
useEffect(() => {
document.title = "React Side Effects Example";
}, []);By default, useEffect runs after every render, but you can control it with dependencies. This helps keep your UI predictable while still handling side effects when you need to.
38. Difference between React and React Native
React is a JavaScript library for building user interfaces on the web. It updates the browser’s DOM efficiently with a virtual DOM and helps you create reusable UI components.
Developers usually combine React with HTML and CSS to build responsive web pages.
React Native, though, is a framework for making native mobile apps on iOS and Android. Instead of rendering to the browser’s DOM, it talks to native components like View and Text.
Both share core ideas like components, props, and state. React builds web UIs, while React Native makes real mobile interfaces.
Example in React:
<div>Hello, Web!</div>Example in React Native:
<Text>Hello, Mobile!</Text>39. Explain the concept of lifting state up.
In React, “lifting state up” means moving shared state to the nearest common parent component. This way, multiple children can access and update the same data through props.
Instead of each child keeping its own version of the data, the parent manages the state and controls updates. The parent passes data and callback functions down as props.
function Parent() {
const [count, setCount] = useState(0);
return (
<>
<ChildDisplay count={count} />
<ChildControl onIncrease={() => setCount(count + 1)} />
</>
);
}40. What is the purpose of React.StrictMode?
React.StrictMode helps developers spot potential problems in React apps during development. It doesn’t change the production build, but it adds extra checks and warnings to encourage best practices.
When you enable it, React highlights components that use unsafe lifecycle methods, deprecated APIs, or patterns that could cause trouble down the road.
To use it, just wrap parts of your app in the <React.StrictMode> component:
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<App />
</React.StrictMode>
);41. How to do testing in React?
Testing React components helps make sure user interfaces work like you expect. Most people use Jest for running tests and React Testing Library for checking component output.
These tools confirm that components render and respond to user actions the right way. A basic test might render a component and check if certain text or elements show up:
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders welcome text', () => {
render(<App />);
const element = screen.getByText(/welcome/i);
expect(element).toBeInTheDocument();
});42. Explain how to fetch data in React.
To fetch data in React, developers usually use the fetch() API or libraries like Axios. Data fetching happens after a component mounts, letting the UI show up first and update when the data arrives.
Most people use the useEffect hook with state variables to manage and display results. Here’s a common pattern:
import { useEffect, useState } from "react";
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("https://api.example.com/users")
.then((res) => res.json())
.then((data) => setUsers(data))
.catch((err) => console.error(err));
}, []);
return <ul>{users.map((u) => <li key={u.id}>{u.name}</li>)}</ul>;
}43. What is reconciliation algorithm?
The reconciliation algorithm in React figures out how the user interface should update when data changes. It compares the previous Virtual DOM to the new one and finds the fewest updates needed to match the changes.
React uses a process called diffing for this. If an element’s type stays the same, React updates its attributes and children. If types change, React replaces the old element to keep things accurate.
// Example
if (prevElement.type === nextElement.type) {
updateElement(prevElement, nextElement);
} else {
replaceElement(prevElement, nextElement);
}44. How to memoize components?
Memoizing a React component helps avoid unnecessary re-renders when its props don’t change. This can boost performance, especially for components that render big lists or do heavy calculations.
Use the React.memo() higher-order component for functional components. It checks the current and previous props and skips rendering if nothing changed.
const UserCard = React.memo(function UserCard({ name }) {
return <div>{name}</div>;
});For expensive values or functions inside a component, the useMemo() and useCallback() hooks can cache results or functions between renders.
Class components can use PureComponent or implement shouldComponentUpdate() to optimize, though honestly, most new code sticks to functional components these days.
45. What is Suspense in React?
React Suspense lets components handle async operations like data loading or code splitting in a tidy way. It allows a component to “pause” rendering until the needed data or code is ready.
When a component suspends, React shows fallback content—like a loading spinner. This makes loading states feel smoother for users.
Developers often combine Suspense with React.lazy() to load components on demand. You can also use it with libraries that support data fetching through Suspense boundaries.
import React, { Suspense, lazy } from 'react';
const UserProfile = lazy(() => import('./UserProfile'));
function App() {
return (
<Suspense fallback={<p>Loading...</p>}>
<UserProfile />
</Suspense>
);
}46. Explain useReducer hook.
The useReducer hook in React manages complex state logic inside functional components. It works a bit like reducers in Redux—actions describe what to change, and a reducer function decides how to update the state.
Developers use it when multiple state variables depend on each other. useReducer takes a reducer function and an initial state value, then returns the current state and a dispatch function.
const [state, dispatch] = useReducer(reducer, initialState);The reducer function gets the current state and an action, then returns a new state. This approach helps keep state updates predictable and code more readable in big components.
47. What are React hooks rules?
React Hooks have specific rules to keep components predictable. You should only call hooks at the top level of a functional component or inside a custom hook.
Never call them inside loops, conditions, or nested functions. That can mess up state between renders.
Hooks work only in React functions—not in regular JavaScript functions or class components. Stick to these rules and your state and lifecycle logic will stay clear.
// Correct usage
function Example() {
const [count, setCount] = useState(0);
}48. How to create custom hooks?
To reuse stateful logic across components, developers create custom hooks in React. A custom hook is just a function that starts with “use”—that naming helps React spot it as a hook.
You can use built-in hooks like useState, useEffect, or useRef inside your custom hook. Here’s a simple counter hook:
import { useState } from "react";
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
const increment = () => setCount(count + 1);
const reset = () => setCount(initialValue);
return { count, increment, reset };
}49. What is the role of ReactDOM?
ReactDOM connects React components to the browser’s Document Object Model (DOM). It updates the DOM efficiently whenever a component’s state or props change.
Developers use ReactDOM to mount React components into specific DOM nodes. The most common way is ReactDOM.render(), which puts the root component into a web page element.
ReactDOM also handles unmounting components and portals, which let you render elements outside the main component tree. For server-side rendering, ReactDOM can render components to static HTML.
import ReactDOM from "react-dom/client";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);50. How to style React components?
You can style React components in several ways, depending on your project and what you like. Common methods include inline styles, external CSS files, CSS Modules, and CSS-in-JS libraries like Styled Components or Emotion.
Inline styles go right on the element using the style attribute and a JavaScript object:
<div style={{ color: 'blue', backgroundColor: 'lightgray' }}>Styled text</div>CSS Modules let you scope styles to prevent naming conflicts. You import them as objects:
import styles from './Button.module.css';
<button className={styles.primary}>Click</button>CSS-in-JS libraries let you define component-level styles in JavaScript. For example, with Styled Components:
import styled from 'styled-components';
const Box = styled.div`padding: 10px; color: green;`;Some folks also use utility frameworks like Tailwind CSS for fast styling.
51. What is the difference between inline and external CSS in React?
Inline CSS in React means you add styles right to an element using the style attribute. You write styles as JavaScript objects, and the property names use camelCase instead of regular CSS syntax.
function Button() {
return <button style={{ backgroundColor: 'blue', color: 'white' }}>Click</button>;
}External CSS lives in a separate .css file, which you import into your component. You then assign class names and manage all your styles in that file.
import './Button.css';
function Button() {
return <button className="btn-primary">Click</button>;
}Inline styling works best for quick tweaks or dynamic values. External CSS is the go-to for bigger projects where you want to keep things consistent and easy to maintain.
Most teams lean toward external files or CSS-in-JS libraries to keep things organized but flexible.
52. Explain the concept of immutability in React state
Immutability in React means you shouldn’t change state values directly. Instead, you make new copies of your state objects or arrays when you need to update them.
This approach lets React spot updates and trigger the right re-renders. React checks object references to see if something changed, so mutating state in place just confuses it and can break your UI updates.
For example:
setTodos([...todos, newTodo]);Here, you’re creating a new array with the new item. Immutability keeps your code predictable and helps you avoid weird side effects.
53. How to optimize React re-rendering?
You can cut down on unnecessary re-renders by using React.memo for functional components. It tells React to only re-render if the props actually change, which is a lifesaver in bigger apps.
Hooks like useCallback and useMemo also help. useCallback keeps your callback functions from being recreated every render, and useMemo does the same for expensive computed values.
Always use stable keys in lists. React relies on them to track which items changed, so it doesn’t have to redraw everything.
{items.map(item => <ListItem key={item.id} data={item} />)}Try not to pass new objects or functions as props unless you really need to. And don’t forget to check your app with React DevTools if things start to feel sluggish.
54. What is event delegation in React?
Event delegation in React means you let a single event listener handle events for lots of child elements. Instead of putting listeners everywhere, React listens at the root and uses its synthetic event system to manage things.
This setup is more efficient and uses less memory. React’s synthetic events also smooth out browser differences, and events bubble up the virtual DOM so you can manage everything in one place.
This pattern shines when you’re creating or changing elements on the fly. Here’s a quick example:
function ItemList() {
const handleClick = (e) => {
if (e.target.tagName === 'LI') {
console.log(e.target.textContent);
}
};
return (
<ul onClick={handleClick}>
<li>Apple</li>
<li>Orange</li>
<li>Banana</li>
</ul>
);
}55. How to implement authentication in React apps?
Authentication controls who can see certain pages in a React app. You can use services like Auth0 or Firebase Authentication, or roll your own with JSON Web Tokens (JWT).
Usually, you’ll have a login form that sends user credentials to an API. The API sends back a token, and your app stores it in local storage or cookies for later.
// Example: storing token after login
loginUser(credentials).then(res => {
localStorage.setItem("token", res.token);
});Protected routes check if there’s a valid token before showing sensitive pages. With React Router, you can redirect users to the login page if they’re not authenticated.
<Route
path="/dashboard"
element={token ? <Dashboard /> : <Navigate to="/login" />}
/>56. What is the importance of keys in dynamic lists?
Keys let React figure out which items in a list changed, got added, or were removed. They act as unique IDs so React only updates what’s necessary, making things faster and keeping component state in sync.
When React compares lists, it matches items by key. If you reuse or skip keys, you might see weird bugs or lose component state.
It’s best to use stable, unique values—like IDs from your data—as keys. Avoid using array indexes if the list can change order.
{items.map((item) => (
<ListItem key={item.id} value={item.name} />
))}57. Explain the usage of defaultProps.
In React, defaultProps sets default values for component props. If a parent doesn’t send a prop, React falls back to the default you set, which helps avoid errors and keeps your components predictable.
With class components, you add defaultProps as a static property on the class.
class Button extends React.Component {
static defaultProps = {
label: 'Click Me',
};
render() {
return <button>{this.props.label}</button>;
}
}In functional components, you can just set the default right in the parameter list. It’s simpler and fits with modern React.
function Button({ label = 'Click Me' }) {
return <button>{label}</button>;
}58. What are React portals used for?
React portals let you render a child component into a different part of the DOM than its parent. You can keep your component structure tidy in React, but place things wherever you want in the actual DOM.
Portals come in handy for stuff like modals, tooltips, or dropdowns that need to pop out of their parent container. They help you dodge styling headaches with overflow or z-index.
You create a portal with ReactDOM.createPortal, passing the child element and the target DOM node.
ReactDOM.createPortal(
<ModalContent />,
document.getElementById('modal-root')
);Even though the element lives outside its parent in the DOM, it still acts like part of the React tree—so state and events work as expected.
59. Difference between stateful and stateless components.
Stateful components manage their own data and can update their output when users interact or something changes. They keep info in local state, and React updates them as needed. You’ll use these for things like forms, counters, or anything interactive.
Stateless components, or functional components, just render UI based on the props they get. They don’t store or change state themselves. Because they’re simpler, they’re easier to test and maintain.
// Stateful Component
class Counter extends React.Component {
state = { count: 0 };
render() {
return <button onClick={() => this.setState({ count: this.state.count + 1 })}>{this.state.count}</button>;
}
}
// Stateless Component
function Greeting(props) {
return <h1>Hello, {props.name}</h1>;
}60. How to handle errors in React?
React handles errors with error boundaries and smart runtime checks. An error boundary is a component that catches errors in its children during rendering or lifecycle methods, so your whole app doesn’t crash.
You make an error boundary as a class component that uses componentDidCatch() and getDerivedStateFromError().
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
console.error(error, info);
}
render() {
if (this.state.hasError) {
return <h2>Something went wrong.</h2>;
}
return this.props.children;
}
}For async code, wrap things in try...catch blocks and log errors for easier debugging.
61. Explain useRef hook and common use cases.
The useRef hook in React gives you a mutable object that sticks around between renders. It lets you store a value without causing a re-render when it changes.
The object has a .current property that holds whatever you want. One of the most common uses is grabbing a DOM element directly—like focusing an input.
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);useRef can also store previous props or state, or keep track of timers. Since it doesn’t trigger re-renders, it’s handy for performance tweaks where you want to avoid unnecessary updates.
62. What is the difference between useLayoutEffect and useEffect?
The useEffect hook runs after React updates the DOM and the browser paints the screen. It works asynchronously, so it won’t block the page from showing updated content. You’ll use it for things like fetching data or setting up subscriptions.
The useLayoutEffect hook runs synchronously after the DOM updates, but before the browser paints. So, any layout changes or measurements happen before users see the screen refresh.
useLayoutEffect(() => {
const height = boxRef.current.offsetHeight;
setHeight(height);
});Since useLayoutEffect blocks painting until it finishes, you should only use it when you really need to—otherwise, it could slow things down.
63. How to pass callbacks as props?
In React, you can send functions from a parent to a child component through props. This lets the child trigger actions in the parent, which is great if the child needs to update state or report something back up.
The parent defines the function, then passes it as a prop. The child calls it when needed—simple as that.
function Parent() {
function handleClick() {
alert("Button clicked!");
}
return <Child onButtonClick={handleClick} />;
}
function Child({ onButtonClick }) {
return <button onClick={onButtonClick}>Click Me</button>;
}Passing callbacks like this keeps your components reusable and makes it easier to manage state changes across your app.
64. Explain the React context and how to consume it
React Context lets you share data across components without passing props through every level. It’s handy for things like authentication, theme, or language—those global values we all end up needing.
You create a context using React.createContext(). That gives you a Context object with both a Provider and a Consumer.
The Provider wraps your component tree and supplies the shared data. To use the context value, just call the useContext hook inside a functional component.
import React, { createContext, useContext } from "react";
const ThemeContext = createContext("light");
function DisplayTheme() {
const theme = useContext(ThemeContext);
return <p>Current theme: {theme}</p>;
}65. What are the limitations of React?
React only handles the view layer. If you want routing, state management, or forms, you’ll need extra tools or libraries, which can make things a bit more complicated.
It leans hard on JavaScript. That means big apps sometimes get tricky to optimize, and careless component design can slow things down with too many re-renders.
React updates fast, but docs and third-party libraries don’t always keep up. Teams often have to spend time updating their codebase just to stay current.
SEO is another pain point in client-side rendered React apps, unless you set up server-side rendering. That adds more setup and maintenance, which isn’t everyone’s favorite task.
// Example: Basic React component (view layer only)
function Greeting({ name }) {
return <h1>Hello, {name}</h1>;
}66. How do you prevent unnecessary renders?
React re-renders components when their state or props change, even if nothing visually changes. To cut down on wasted renders, you can control when and how components update.
One popular trick is wrapping functional components with React.memo(). This skips re-renders if props haven’t changed. For functions or values passed as props, useCallback() and useMemo() help keep references stable.
Keeping state local to the smallest component that needs it is also a big help. This limits how often parent updates ripple down and trigger child re-renders.
const Child = React.memo(({ value }) => <div>{value}</div>);React’s Profiler can show you which components render most often. Combine profiling with memoization and tidy state management, and you’ll keep things snappy.
67. Explain props drilling and how to avoid it.
Props drilling happens when you pass data from a parent all the way down through several layers, just so a deep child can use it. This gets messy fast as your project grows.
To dodge props drilling, use the React Context API. It lets you share data across components without passing props at every level.
const UserContext = React.createContext();
function App() {
return (
<UserContext.Provider value="John">
<Profile />
</UserContext.Provider>
);
}
function Profile() {
const name = React.useContext(UserContext);
return <h1>{name}</h1>;
}State management tools like Redux, Zustand, or Recoil also help by centralizing shared state and making it available wherever you need it.
68. What tools do you use for React debugging?
Most developers use React Developer Tools, a browser extension for Chrome, Firefox, and Edge. It lets you inspect your React component tree, poke around props and state, and track updates live. You can also use it with React Native via React Native DevTools.
Redux DevTools is great for monitoring and replaying actions in Redux apps. Time-travel debugging? Super handy for finding logic bugs.
If you’re hunting performance issues, tools like why-did-you-render flag unnecessary re-renders. For logging and monitoring, Sentry and LogRocket capture runtime errors and user sessions.
Sometimes, a simple console log does the trick:
console.log('Component state:', this.state);69. What is the role of Babel in React?
Babel is a JavaScript compiler that lets React developers write modern code and still support old browsers. It converts new JavaScript features, like ES6, into code every browser understands.
For React, Babel also turns JSX into regular JavaScript. JSX elements become React.createElement() calls, which React knows how to handle.
Using presets like @babel/preset-env and @babel/preset-react, you can tell Babel to process both modern JavaScript and React syntax.
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}70. Explain JSX transpilation
JSX, or JavaScript XML, lets you write HTML-like code right inside JavaScript. It makes UI code easier to read and organize, but browsers don’t understand JSX by default.
Before the browser can run it, JSX needs to be transpiled into regular JavaScript. Tools like Babel handle this, turning JSX into function calls that React can process.
Take this JSX, for example:
const element = <h1>Hello, React!</h1>;After transpilation, it becomes:
const element = React.createElement('h1', null, 'Hello, React!');This way, you get to write clean code while still delivering something the browser can run.
71. How to handle forms validation in React?
Form validation in React checks that user input meets certain rules before you submit it. This prevents bad data and makes forms way more usable. You can validate forms by hand or use HTML attributes like required and minLength.
Controlled components are the usual way—form inputs rely on React state, so you can manage each field’s value and validation logic directly. Here’s a quick example:
function LoginForm() {
const [email, setEmail] = React.useState("");
const [error, setError] = React.useState("");
function handleSubmit(e) {
e.preventDefault();
if (!email.includes("@")) setError("Enter a valid email.");
}
return (
<form onSubmit={handleSubmit}>
<input value={email} onChange={(e) => setEmail(e.target.value)} />
<p>{error}</p>
</form>
);
}For bigger forms, libraries like Formik, Yup, or React Hook Form can save you a ton of hassle.
72. How to structure a React project?
Most developers organize React projects to keep things maintainable and scalable. A good structure helps you and your team find files quickly and understand how everything fits together.
Usually, you’ll see folders like src, components, pages, hooks, and utils. Each folder groups related stuff and keeps logic tidy.
src/
├── components/
├── pages/
├── hooks/
├── utils/
├── assets/
├── App.js
└── index.jsSome teams go for a “feature-based” structure, where all files for a feature—components, styles, tests—live together. That can make it easier to work on one feature without messing up others.
Whatever you pick, just keep naming consistent, components modular, and import paths clear. It’ll pay off as your app grows.
73. What is the difference between React’s setState and useState?
setState is for class components, while useState is a Hook for functional components. Both manage state, but they work a bit differently depending on what kind of component you’re using.
With class components, setState merges updates into the existing state object. It only updates the keys you specify and can batch updates for better performance.
this.setState({ count: this.state.count + 1 });In functional components, useState gives you a state variable and an update function. The update replaces the current state with your new value—it doesn’t merge objects for you.
const [count, setCount] = useState(0);
setCount(count + 1);74. How does React update the UI?
React updates the UI by comparing the current and new states of your components. It uses a virtual DOM, which is just an in-memory version of the real DOM, to track changes efficiently.
When state or props change, React builds a new virtual DOM tree. It compares this to the old one to spot differences—a process called reconciliation. Only the changed parts of the real DOM get updated.
This approach cuts down on expensive DOM operations. You can trigger updates using setState() or Hooks like useState.
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
}Here, React only updates the count text, not the entire button. It’s pretty slick.
75. Explain Suspense for data fetching.
React Suspense lets you pause rendering a component until data or another async resource is ready. It makes handling loading states easier, you don’t have to sprinkle manual checks all over your component.
To use Suspense, wrap part of your component tree with the <Suspense> tag and set a fallback UI. The fallback shows while data loads, and React automatically continues rendering once the data arrives.
For example:
<Suspense fallback={<p>Loading...</p>}>
<UserProfile />
</Suspense>Suspense works nicely with concurrent rendering and server components. It gives users a smoother experience, showing either a loading state or the finished UI—no jarring changes. Many teams pair it with Error Boundaries to catch errors while fetching data.
Conclusion
Getting ready for a React.js interview takes steady practice. You really need a solid grip on the core topics.
Spend time reviewing state management, hooks, and the component lifecycle. These areas help you explain your thinking and choices clearly—at least, that’s the goal.
You may also like to read:
- Remove None Values from a List in Python
- Difference Between “is None” and “== None” in Python
- Check if a Variable is Not None in Python
- Check If a Variable is None

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.