React.js Interview Guide (Beginner → Deep)
SECTION 1: React Basics
Q1. What is React?
React is a JavaScript library (not a full framework) for building user interfaces, developed by Facebook (Meta). It lets you build reusable components and efficiently updates the UI when data changes, using a Virtual DOM.
Q2. What is the Virtual DOM? How does it work?
The Virtual DOM (VDOM) is a lightweight, in-memory copy of the real DOM. When state changes:
- React creates a new Virtual DOM tree.
- It compares (“diffs”) the new tree with the previous one.
- It calculates the minimal set of changes needed (reconciliation).
- Only those changes are applied to the real DOM (batched updates).
This is faster than direct DOM manipulation because real DOM operations are expensive, while VDOM comparisons happen in memory.
Q3. What is JSX?
JSX (JavaScript XML) is a syntax extension that lets you write HTML-like code inside JavaScript. It gets compiled (via Babel) into React.createElement() calls.
const element = <h1>Hello, World!</h1>;// Compiles to:
const element = React.createElement('h1', null, 'Hello, World!');Q4. What are Components in React?
Components are independent, reusable pieces of UI. Two types:
- Functional Components (modern standard, use Hooks)
- Class Components (older style, use lifecycle methods)
// Functional Component
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}// Class Component
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}Q5. What is the difference between an Element and a Component?
- An Element is a plain object describing what you want to see on screen (
<h1>Hello</h1>) — it's immutable and cheap to create. - A Component is a function or class that returns elements. Components can be reused and take props.
Q6. What are Props?
Props (“properties”) are read-only inputs passed from a parent component to a child component to configure/customize it. Props cannot be modified by the child component.
function Greeting({ name }) {
return <p>Hello, {name}!</p>;
}<Greeting name="Alice" />Q7. What is State in React?
State is data that is local to a component and can change over time (e.g., due to user interaction). Unlike props, state is managed within the component and can be updated using setState (class) or useState (functional).
function Counter() {
const [count, setCount] = React.useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}Q8. Difference between Props and State?
PropsStatePassed from parent to childManaged within the componentRead-only (immutable)Mutable (via setter function)Used to configure a componentUsed to track dynamic dataChanging props re-renders childChanging state re-renders same component
Q9. What is the difference between a Controlled and Uncontrolled Component?
- Controlled Component: Form data is handled by React state — the input’s value is always driven by state.
- Uncontrolled Component: Form data is handled by the DOM itself, accessed via
ref.
// Controlled
function ControlledInput() {
const [value, setValue] = React.useState('');
return <input value={value} onChange={(e) => setValue(e.target.value)} />;
}// Uncontrolled
function UncontrolledInput() {
const inputRef = React.useRef();
return <input ref={inputRef} />;
}Q10. What are Fragments in React?
Fragments let you group multiple elements without adding an extra node to the DOM.
function List() {
return (
<>
<li>Item 1</li>
<li>Item 2</li>
</>
);
}SECTION 2: Handling Events, Lists, Conditional Rendering
Q11. How do you handle events in React?
React uses camelCase event names and passes a function reference (not a string) as the handler — this is a SyntheticEvent wrapper around the native event for cross-browser consistency.
function Button() {
const handleClick = (e) => {
console.log('Button clicked', e);
};
return <button onClick={handleClick}>Click Me</button>;
}Q12. How do you render lists in React? Why do list items need a key?
Use .map() to render arrays of data. Each item needs a unique key prop so React can efficiently identify which items changed, were added, or removed during re-renders — without keys, React may re-render items unnecessarily or lose input state.
function TodoList({ todos }) {
return (
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
);
}⚠️ Never use array index as key if the list can be reordered/filtered — it causes bugs with component state.
Q13. How do you do conditional rendering in React?
function Greeting({ isLoggedIn }) {
// if/else
if (isLoggedIn) return <h1>Welcome back!</h1>;
return <h1>Please sign in.</h1>;
}function Notification({ count }) {
// ternary
return <div>{count > 0 ? `${count} new messages` : 'No messages'}</div>;
}function Alert({ show }) {
// && operator
return <div>{show && <p>Warning message!</p>}</div>;
}
SECTION 3: React Hooks (Core Concept for Modern React)
Q14. What are Hooks? Why were they introduced?
Hooks are functions that let you use state and other React features in functional components without writing a class. Introduced in React 16.8 to:
- Avoid complex class components and
thisbinding issues - Enable reusing stateful logic between components (without patterns like HOCs/render props)
- Split code by concern rather than lifecycle method
Q15. What is useState?
Lets you add state to a functional component. Returns an array: [currentValue, setterFunction].
const [count, setCount] = useState(0);// Functional update (safer when new state depends on old state)
setCount(prevCount => prevCount + 1);Q16. What is useEffect? Explain its dependency array.
useEffect lets you perform side effects (data fetching, subscriptions, DOM manipulation, timers) in functional components. It runs after render.
useEffect(() => {
console.log('Runs after every render');
});useEffect(() => {
console.log('Runs only once, on mount');
}, []);useEffect(() => {
console.log('Runs when `count` changes');
}, [count]);useEffect(() => {
const timer = setInterval(() => console.log('tick'), 1000);
return () => clearInterval(timer); // cleanup function (runs on unmount / before next effect)
}, []);
Dependency ArrayBehaviorNo arrayRuns after every render[] (empty)Runs once after initial mount[value1, value2]Runs when any listed value changes
Q17. What is useContext? Why is it used?
useContext lets components read values from React Context without manually passing props down through every level ("prop drilling").
const ThemeContext = React.createContext('light');function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}function Toolbar() {
const theme = React.useContext(ThemeContext);
return <div>Current theme: {theme}</div>;
}
Q18. What is useRef? Give use cases.
useRef returns a mutable object ({ current: value }) that persists across renders without causing a re-render when changed. Common uses:
- Accessing DOM elements directly
- Storing a mutable value that doesn’t trigger re-render (like a timer ID or previous value)
function TextInput() {
const inputRef = React.useRef(null);
const focusInput = () => inputRef.current.focus();
return (
<>
<input ref={inputRef} />
<button onClick={focusInput}>Focus Input</button>
</>
);
}Q19. Difference between useRef and useState?
useStateuseRefTriggers re-render on changeDoes NOT trigger re-renderValue is “immutable” per renderValue is mutable, persists directlyUsed for data shown in UIUsed for DOM refs / values you don’t need to display
Q20. What is useMemo? When should you use it?
useMemo memoizes (caches) a computed value, recalculating it only when its dependencies change — used to avoid expensive recalculations on every render.
const expensiveResult = useMemo(() => {
return computeExpensiveValue(a, b);
}, [a, b]);Q21. What is useCallback? How is it different from useMemo?
useCallback memoizes a function (returns the same function reference between renders unless dependencies change), commonly used to prevent unnecessary re-renders of child components that receive callbacks as props.
useMemo→ memoizes a valueuseCallback→ memoizes a function
const handleClick = useCallback(() => {
doSomething(a, b);
}, [a, b]);Q22. What is useReducer? When would you use it instead of useState?
useReducer is an alternative to useState for managing complex state logic (e.g., multiple sub-values, or next state depends on previous state in complex ways) — similar to Redux's reducer pattern.
function reducer(state, action) {
switch (action.type) {
case 'increment': return { count: state.count + 1 };
case 'decrement': return { count: state.count - 1 };
default: throw new Error();
}
}function Counter() {
const [state, dispatch] = React.useReducer(reducer, { count: 0 });
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>−</button>
</>
);
}Q23. What are Custom Hooks? Why create one?
Custom Hooks are reusable functions (prefixed with use) that let you extract and share stateful logic between components.
function useWindowWidth() {
const [width, setWidth] = React.useState(window.innerWidth);React.useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []); return width;
}// Usage
function MyComponent() {
const width = useWindowWidth();
return <p>Window width: {width}</p>;
}
Q24. What are the Rules of Hooks?
- Only call Hooks at the top level — not inside loops, conditions, or nested functions.
- Only call Hooks from React function components or custom Hooks — not regular JS functions.
(This ensures Hooks are called in the same order on every render, which React relies on internally to track state correctly.)
SECTION 4: Component Lifecycle
Q25. What are the phases of a Component’s Lifecycle?
- Mounting — component is created and inserted into the DOM
- Updating — component re-renders due to props/state change
- Unmounting — component is removed from the DOM
Q26. Explain Class Component lifecycle methods and their Hook equivalents.
Class Lifecycle MethodFunctional Hook Equivalentconstructor()useState() initializationcomponentDidMount()useEffect(() => {...}, [])componentDidUpdate()useEffect(() => {...}, [dep])componentWillUnmount()useEffect(() => { return () => {...} }, []) (cleanup)shouldComponentUpdate()React.memo()
// Class version
class Timer extends React.Component {
componentDidMount() {
this.timer = setInterval(() => console.log('tick'), 1000);
}
componentWillUnmount() {
clearInterval(this.timer);
}
render() { return <div>Timer running</div>; }
}// Functional (Hooks) version — equivalent behavior
function Timer() {
useEffect(() => {
const timer = setInterval(() => console.log('tick'), 1000);
return () => clearInterval(timer);
}, []);
return <div>Timer running</div>;
}SECTION 5: Component Communication & Patterns
Q27. How do you pass data from Child to Parent?
By passing a callback function as a prop from parent to child; the child calls it with data.
function Parent() {
const handleData = (data) => console.log('Received:', data);
return <Child onSendData={handleData} />;
}function Child({ onSendData }) {
return <button onClick={() => onSendData('Hello Parent!')}>Send</button>;
}Q28. What is “Lifting State Up”?
When multiple components need to share the same changing data, the state is moved (“lifted”) to their closest common parent, which then passes it down via props.
Q29. What is Prop Drilling? How can you avoid it?
Prop drilling is passing props through multiple nested components that don’t need the data themselves, just to reach a deeply nested child. Solved using:
- Context API (
useContext) - State management libraries (Redux, Zustand, Recoil)
- Component composition
Q30. What is the Context API?
A built-in React feature for sharing data (like theme, auth user, language) across the component tree without prop drilling.
const UserContext = React.createContext(null);function App() {
const [user] = React.useState({ name: 'Alice' });
return (
<UserContext.Provider value={user}>
<Dashboard />
</UserContext.Provider>
);
}function Dashboard() {
const user = React.useContext(UserContext);
return <p>Welcome, {user.name}</p>;
}
Q31. What are Higher-Order Components (HOC)?
A HOC is a function that takes a component and returns a new, enhanced component — used to reuse component logic.
function withLogger(WrappedComponent) {
return function EnhancedComponent(props) {
console.log('Rendering', WrappedComponent.name);
return <WrappedComponent {...props} />;
};
}const EnhancedButton = withLogger(Button);Get Deepaksingh’s stories in your inbox
Join Medium for free to get updates from this writer.
Q32. What is the Render Props pattern?
A technique for sharing code between components using a prop whose value is a function that returns JSX.
function DataProvider({ render }) {
const [data] = React.useState('Some Data');
return render(data);
}<DataProvider render={(data) => <p>{data}</p>} />Q33. What is Composition vs Inheritance in React?
React strongly favors composition over inheritance for code reuse — building complex UIs by combining smaller components, rather than extending classes.
function Card({ children }) {
return <div className="card">{children}</div>;
}<Card>
<h2>Title</h2>
<p>Content inside the card</p>
</Card>SECTION 6: Performance Optimization
Q34. What is React.memo()?
A higher-order component that memoizes a functional component — it skips re-rendering if props haven’t changed (shallow comparison).
const Child = React.memo(function Child({ name }) {
console.log('Child rendered');
return <p>{name}</p>;
});Q35. How do you prevent unnecessary re-renders in React?
- Use
React.memo()for components - Use
useMemo()for expensive computed values - Use
useCallback()for function props passed to memoized children - Avoid creating new objects/arrays/functions inline in JSX (causes new references every render)
- Use proper
keyprops in lists - Split large components into smaller ones
Q36. What is Code Splitting? How do you implement it in React?
Code splitting breaks your bundle into smaller chunks loaded on demand, improving initial load time — done via dynamic import() and React.lazy().
const ProfilePage = React.lazy(() => import('./ProfilePage'));function App() {
return (
<React.Suspense fallback={<div>Loading...</div>}>
<ProfilePage />
</React.Suspense>
);
}Q37. What is React.Suspense?
A component that lets you “wait” for some asynchronous operation (like lazy-loaded components or data fetching in newer React versions) and show a fallback UI (like a spinner) while waiting.
Q38. What is Reconciliation? What is the “Diffing Algorithm”?
Reconciliation is the process React uses to update the DOM by comparing the new Virtual DOM tree with the previous one. React’s diffing algorithm makes this efficient (O(n) instead of O(n³)) through two assumptions:
- Two elements of different types produce different trees — React tears down the old tree and builds a new one.
- Elements with a stable
keyprop stay identified as the same element across renders, allowing React to reuse and update it instead of recreating it.
SECTION 7: Routing (React Router)
Q39. How do you set up routing in a React app?
Using React Router (react-router-dom):
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/user/:id" element={<UserProfile />} />
</Routes>
</BrowserRouter>
);
}Q40. How do you access route parameters and navigate programmatically?
import { useParams, useNavigate } from 'react-router-dom';function UserProfile() {
const { id } = useParams(); // access :id from URL
const navigate = useNavigate(); return (
<div>
<p>User ID: {id}</p>
<button onClick={() => navigate('/')}>Go Home</button>
</div>
);
}
Q41. What is a Protected/Private Route?
A route that only renders if the user meets certain conditions (e.g., is authenticated), otherwise redirects.
function ProtectedRoute({ isAuthenticated, children }) {
return isAuthenticated ? children : <Navigate to="/login" />;
}<Route path="/dashboard" element={
<ProtectedRoute isAuthenticated={isLoggedIn}>
<Dashboard />
</ProtectedRoute>
} />SECTION 8: State Management (Redux / Global State)
Q42. Why use Redux (or similar) instead of just Context/useState?
Context + useState works well for simple/medium apps, but for large apps with complex, frequently-updated global state, Redux offers:
- A single predictable state container
- Time-travel debugging (Redux DevTools)
- Clear unidirectional data flow
- Middleware support (for async logic, logging, etc.)
Context re-renders all consumers on any value change and isn’t optimized for frequent updates — Redux (with selectors) avoids unnecessary re-renders more efficiently.
Q43. What are the core concepts of Redux?
- Store: single source of truth holding the entire app state
- Action: plain object describing what happened (
{ type: 'INCREMENT' }) - Reducer: pure function that takes current state + action, returns new state
- Dispatch: method to send actions to the store
// Reducer
function counterReducer(state = { count: 0 }, action) {
switch (action.type) {
case 'increment': return { count: state.count + 1 };
default: return state;
}
}// Store
const store = Redux.createStore(counterReducer);
store.dispatch({ type: 'increment' });Q44. What is Redux Toolkit (RTK)? Why is it recommended over plain Redux?
RTK is the official, opinionated toolset for Redux that simplifies setup — reduces boilerplate, includes createSlice, configureStore, built-in Immer (allows "mutating" syntax that's actually immutable under the hood), and createAsyncThunk for async logic.
import { createSlice, configureStore } from '@reduxjs/toolkit';const counterSlice = createSlice({
name: 'counter',
initialState: { count: 0 },
reducers: {
increment: (state) => { state.count += 1; }, // looks mutable, is actually immutable (Immer)
},
});const store = configureStore({ reducer: counterSlice.reducer });
export const { increment } = counterSlice.actions;
Q45. How do you connect a React component to Redux?
Using hooks from react-redux: useSelector and useDispatch.
import { useSelector, useDispatch } from 'react-redux';
import { increment } from './counterSlice';function Counter() {
const count = useSelector((state) => state.counter.count);
const dispatch = useDispatch(); return (
<button onClick={() => dispatch(increment())}>
Count: {count}
</button>
);
}
Q46. What are alternatives to Redux for state management?
- Context API (built-in, good for simple/medium state)
- Zustand (lightweight, minimal boilerplate)
- Recoil (atom-based state, made by Facebook)
- MobX (reactive state management)
- Jotai (atomic state, similar to Recoil)
SECTION 9: Forms, Refs, and Data Fetching
Q47. How do you handle forms in React?
function SignupForm() {
const [formData, setFormData] = React.useState({ name: '', email: '' });const handleChange = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
}; const handleSubmit = (e) => {
e.preventDefault();
console.log(formData);
}; return (
<form onSubmit={handleSubmit}>
<input name="name" value={formData.name} onChange={handleChange} />
<input name="email" value={formData.email} onChange={handleChange} />
<button type="submit">Submit</button>
</form>
);
}
Q48. How do you fetch data (API calls) in React?
Typically done inside useEffect:
function UserList() {
const [users, setUsers] = React.useState([]);
const [loading, setLoading] = React.useState(true);React.useEffect(() => {
fetch('https://api.example.com/users')
.then((res) => res.json())
.then((data) => {
setUsers(data);
setLoading(false);
})
.catch((err) => console.error(err));
}, []); if (loading) return <p>Loading...</p>;
return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}
For larger apps, libraries like React Query (TanStack Query) or SWR are preferred — they handle caching, re-fetching, loading/error states automatically.
Q49. What are Error Boundaries?
Error Boundaries are class components that catch JavaScript errors anywhere in their child component tree, log them, and display a fallback UI instead of crashing the whole app. (Hooks currently cannot create error boundaries — must be a class component.)
class ErrorBoundary extends React.Component {
state = { hasError: false };static getDerivedStateFromError() {
return { hasError: true };
} componentDidCatch(error, info) {
console.error(error, info);
} render() {
if (this.state.hasError) return <h1>Something went wrong.</h1>;
return this.props.children;
}
}
SECTION 10: Deep / Advanced React Concepts
Q50. What is the difference between React.PureComponent and React.Component?
PureComponent automatically implements shouldComponentUpdate() with a shallow prop/state comparison, preventing unnecessary re-renders — regular Component re-renders on every parent update regardless.
Q51. What is Reconciliation Key stability, and why can using array index as key cause bugs?
If list order changes (items inserted/removed/reordered) and you use the array index as key, React may match the wrong old element to the wrong new data — causing incorrect DOM updates, lost input focus, or stale component state, since React tracks elements by key, not by content.
Q52. What is the difference between useLayoutEffect and useEffect?
useEffect— runs asynchronously, after the browser has painted the screen. Good for most side effects.useLayoutEffect— runs synchronously, immediately after DOM mutations but before the browser paints. Used when you need to measure/mutate the DOM before the user sees a flicker (e.g., measuring element size, adjusting scroll position).
Q53. What is Server-Side Rendering (SSR)? Why use it?
SSR renders React components to HTML on the server before sending them to the browser (instead of rendering entirely client-side), improving:
- Initial page load / perceived performance
- SEO (search engines can crawl rendered content)
Frameworks like Next.js provide built-in SSR support.
Q54. What is Hydration in React?
Hydration is the process where React “attaches” event listeners and makes a server-rendered HTML page interactive on the client, without re-rendering the DOM from scratch — used after SSR delivers static HTML.
Q55. What is the difference between CSR, SSR, and SSG?
TypeDescriptionCSR (Client-Side Rendering)HTML is mostly empty; JS builds the UI in the browserSSR (Server-Side Rendering)HTML is generated on the server per requestSSG (Static Site Generation)HTML is pre-built at build time, served as static files (fastest, best for content that doesn’t change often)
Q56. What is React Fiber?
React Fiber is the reimplementation of React’s core reconciliation algorithm (since React 16), designed to enable:
- Incremental rendering — splitting rendering work into chunks
- Pausing, aborting, or reusing work as needed
- Assigning priority to different types of updates (e.g., animations vs. data fetching) This is what enables features like Concurrent Mode / Suspense.
Q57. What is Concurrent Rendering (React 18)?
A set of new capabilities that let React prepare multiple versions of the UI at the same time, without blocking the main thread — allowing React to interrupt, pause, resume, or abandon a render, keeping the app responsive even during large updates.
Q58. What is useTransition (React 18)?
Lets you mark certain state updates as non-urgent (“transitions”), so React can keep the UI responsive (e.g., keep typing smooth) while a slower update (like filtering a large list) happens in the background.
const [isPending, startTransition] = React.useTransition();function handleChange(e) {
const value = e.target.value;
startTransition(() => {
setFilteredList(filterBigList(value));
});
}Q59. What is useId (React 18)?
Generates unique, stable IDs for accessibility attributes (like linking a <label> to an <input>), safe for use with SSR (avoids ID mismatches between server and client).
Q60. What is the difference between key and ref?
key— special prop React uses internally to track list items during reconciliation; not accessible inside the component.ref— used to directly access a DOM node or component instance.
Q61. How do you optimize a React app that’s rendering a huge list (e.g., 10,000 items)?
Use virtualization/windowing — only render the items currently visible in the viewport, using libraries like react-window or react-virtualized.
import { FixedSizeList as List } from 'react-window';<List height={400} itemCount={10000} itemSize={35} width={300}>
{({ index, style }) => <div style={style}>Row {index}</div>}
</List>Q62. What is the difference between React.StrictMode and normal rendering?
StrictMode is a development-only tool that helps detect potential problems — it intentionally double-invokes certain functions (like component render, some hooks) to help surface side effects that aren't pure. It does not render any visible UI and has no effect in production builds.
Q63. How does React batch state updates?
React groups multiple setState calls made within the same event handler into a single re-render for performance. Since React 18, this batching happens automatically even inside promises, timeouts, and native event handlers (previously it only worked inside React event handlers).
function handleClick() {
setCount(c => c + 1);
setFlag(f => !f);
// React 18: only ONE re-render, even though two states changed
}Q64. What is the difference between React.createElement and ReactDOM.createRoot/render?
React.createElement()— creates a Virtual DOM element/object (what JSX compiles to).ReactDOM.createRoot(container).render(element)— takes that Virtual DOM tree and actually mounts/renders it into the real DOM at the specified container.







