React Interview Questions - Hooks (31-60)
Master React Hooks for FAANG interviews: useState, useEffect, useContext, useReducer, useCallback, useMemo, useRef, custom hooks, and more with practical examples.
Master React Hooks for FAANG interviews: useState, useEffect, useContext, useReducer, useCallback, useMemo, useRef, custom hooks, and more with practical examples. This interview-focused guide covers essential react interview questions - hooks (31-60) concepts for technical interviews.
React Interview Questions - Hooks (31-60)
React Hooks are a game-changer for functional components, enabling us to use state and other React features without writing classes.
Question 31: What are React Hooks?
Hooks are functions that let you "hook into" React state and lifecycle features from functional components. They were introduced in React 16.8.
Example:
import { useState, useEffect } from 'react';
function Counter() {
const [count, setCount] = useState(0); // useState hook
useEffect(() => { // useEffect hook
document.title = `Count: ${count}`;
}, [count]);
return <button onClick={() => setCount(c => c + 1)}>Count: {count}</button>;
}
Question 32: Rules of Hooks
There are two main rules to follow when using hooks:
- Only call Hooks at the top level (not inside loops, conditions, or nested functions)
- Only call Hooks from React functional components or custom hooks
Why?
React relies on the order of hook calls to match state to the correct component.
Question 33: Explain useState Hook
useState lets you add state to functional components. It returns a state variable and a setter function.
Example:
import { useState } from 'react';
function TextInput() {
const [text, setText] = useState(''); // Initial value
const handleChange = (e) => setText(e.target.value);
return <input value={text} onChange={handleChange} />;
}
Functional Updates:
Use when new state depends on previous state:
setCount(prevCount => prevCount + 1);
Question 34: Explain useEffect Hook
useEffect lets you perform side effects in functional components (e.g., data fetching, DOM manipulation, subscriptions).
Example (Data Fetching):
import { useState, useEffect } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
// Side effect
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => setUser(data));
}, [userId]); // Dependency array
if (!user) return 'Loading...';
return <div>{user.name}</div>;
}
Question 35: Dependency Array in useEffect
The dependency array tells React when to re-run the effect:
- Empty array
[]: Effect runs only once (after first render) - With dependencies
[x, y]: Runs when x or y changes - No array: Runs after every render
Example (Cleanup):
useEffect(() => {
const interval = setInterval(() => {
console.log('Tick');
}, 1000);
// Cleanup function (runs before unmount or before re-running effect)
return () => clearInterval(interval);
}, []);
Question 36: Explain useContext Hook
useContext lets you read context and subscribe to its changes without using a <Context.Consumer> component.
Example:
import { createContext, useContext, useState } from 'react';
const ThemeContext = createContext('light');
function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={theme}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
const theme = useContext(ThemeContext); // Use context
return <div className={`theme-${theme}`}>Toolbar</div>;
}
Question 37: Explain useReducer Hook
useReducer is an alternative to useState for managing complex state logic (like reducers in Redux).
Example:
import { useReducer } from 'react';
const initialState = { count: 0 };
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] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
}
Question 38: Explain useCallback Hook
useCallback memoizes a callback function, preventing unnecessary re-renders of child components that depend on it.
Example:
import { useState, useCallback } from 'react';
function TodoList() {
const [todos, setTodos] = useState([]);
const addTodo = useCallback(() => {
setTodos(prev => [...prev, 'New Todo']);
}, []); // No dependencies = memoized once
return <TodoForm onAdd={addTodo} />; // Won't cause unnecessary re-renders
}
Question 39: Explain useMemo Hook
useMemo memoizes the result of a computation, preventing expensive calculations on every render.
Example:
import { useMemo } from 'react';
function ProductList({ products, filter }) {
// Expensive calculation: Filter products
const filteredProducts = useMemo(() => {
return products.filter(product =>
product.name.toLowerCase().includes(filter.toLowerCase())
);
}, [products, filter]); // Only recalculate when products or filter changes
return <ul>{filteredProducts.map(p => <li key={p.id}>{p.name}</li>)}</ul>;
}
Question 40: Explain useRef Hook
useRef returns a mutable ref object whose .current property persists for the full lifetime of the component.
Common Uses:
- Accessing DOM elements
- Storing mutable values that don't cause re-renders
Example (DOM Access):
import { useRef, useEffect } from 'react';
function InputFocus() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return <input ref={inputRef} type="text" />;
}
Example (Mutable Value):
import { useRef } from 'react';
function Counter() {
const countRef = useRef(0);
const handleClick = () => {
countRef.current++;
console.log(countRef.current); // Updates without re-render!
};
return <button onClick={handleClick}>Count (no re-render)</button>;
}
Question 41: Explain useImperativeHandle Hook
useImperativeHandle customizes the instance value exposed to parent components when using ref.
Example:
import { forwardRef, useImperativeHandle, useRef } from 'react';
const FancyInput = forwardRef((props, ref) => {
const inputRef = useRef(null);
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
inputRef.current.style.border = '2px solid blue';
}
}));
return <input ref={inputRef} {...props} />;
});
// Usage
function App() {
const fancyInputRef = useRef(null);
return (
<div>
<FancyInput ref={fancyInputRef} />
<button onClick={() => fancyInputRef.current.focus()}>Focus Input</button>
</div>
);
}
Question 42: Explain useLayoutEffect Hook
useLayoutEffect runs synchronously after all DOM mutations, but before the browser paints. It's useful for reading DOM layout before the user sees it.
Difference from useEffect:
useEffect: Runs asynchronously after paintuseLayoutEffect: Runs synchronously before paint
Example:
import { useLayoutEffect } from 'react';
function Tooltip({ children }) {
const tooltipRef = useRef(null);
useLayoutEffect(() => {
// Read height before render to position correctly
console.log(tooltipRef.current.clientHeight);
}, []);
return <div ref={tooltipRef}>{children}</div>;
}
Question 43: Explain useDebugValue Hook
useDebugValue lets you display a label for custom hooks in React DevTools.
Example:
import { useState, useDebugValue } from 'react';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
// Show label in DevTools
useDebugValue(isOnline ? 'Online' : 'Offline');
// ... (useEffect here)
return isOnline;
}
Question 44: Custom Hooks
Custom Hooks let you extract component logic into reusable functions. They start with use.
Example (useLocalStorage):
import { useState } from 'react';
function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (e) {
return initialValue;
}
});
const setStoredValue = (newValue) => {
try {
setValue(newValue);
window.localStorage.setItem(key, JSON.stringify(newValue));
} catch (e) {
console.error(e);
}
};
return [value, setStoredValue];
}
// Usage
function App() {
const [theme, setTheme] = useLocalStorage('theme', 'light');
return <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Toggle {theme}
</button>;
}
Question 45: useState vs useReducer
| useState | useReducer |
|---|---|
| Simple state logic | Complex state logic |
| Individual state values | State transitions via reducer function |
| Easier for beginners | Great for predictable state changes |
| Good for basic components | Good for Redux-like patterns without Redux |
When to use which:
- Use
useStatefor simple state (e.g., boolean, string, number) - Use
useReducerwhen state depends on previous state, or when you have complex logic
Question 46: useEffect Cleanup Function
Cleanup function runs when:
- The component unmounts
- The effect runs again (before the new effect)
Example (Subscription Cleanup):
import { useState, useEffect } from 'react';
function ChatRoom({ roomId }) {
const [messages, setMessages] = useState([]);
useEffect(() => {
// Subscribe to chat
const subscription = subscribeToChat(roomId, handleMessage);
// Cleanup
return () => {
subscription.unsubscribe();
};
}, [roomId]); // Re-run effect if roomId changes
return <div>Messages: {messages.length}</div>;
}
Question 47: useEffect for Multiple Effects
You can have multiple useEffect calls in one component to separate concerns.
Example:
function App() {
// Effect 1: Title update
useEffect(() => {
document.title = 'My App';
}, []);
// Effect 2: Data fetch
useEffect(() => {
fetchData();
}, []);
return <div>My App</div>;
}
Question 48: How to fetch data with useEffect
There are 3 common patterns:
Pattern 1: Simple Fetch
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => setUser(data));
}, [userId]);
Pattern 2: Async/Await (with cleanup)
useEffect(() => {
let controller = new AbortController();
const fetchUser = async () => {
try {
const res = await fetch(`/api/users/${userId}`, {
signal: controller.signal
});
const data = await res.json();
setUser(data);
} catch (e) {
if (e.name !== 'AbortError') console.error(e);
}
};
fetchUser();
return () => controller.abort(); // Cancel fetch on unmount
}, [userId]);
Question 49: React.memo and useCallback
React.memo memoizes components, useCallback memoizes functions - use them together!
Example:
import { useState, useCallback, memo } from 'react';
const Button = memo(({ onClick, children }) => {
console.log('Button rendered');
return <button onClick={onClick}>{children}</button>;
});
function App() {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
// Memoize handleClick!
const handleClick = useCallback(() => setCount(c => c + 1), []);
return (
<div>
<Button onClick={handleClick}>Count: {count}</Button>
<input value={text} onChange={(e) => setText(e.target.value)} />
</div>
);
}
Question 50: How to prevent re-renders in React
- Use
React.memofor components - Use
useCallbackfor callbacks - Use
useMemofor computations - Use state sparingly
- Avoid passing new objects/arrays as props
Question 51: Explain useDeferredValue Hook
useDeferredValue lets you defer updating a non-urgent part of the UI, allowing urgent updates (like typing) to happen first.
Example:
import { useState, useDeferredValue } from 'react';
function SearchResults({ query }) {
const deferredQuery = useDeferredValue(query); // Defer
const results = useMemo(() =>
searchProducts(deferredQuery),
[deferredQuery]
);
return <div>{results.map(p => <p key={p.id}>{p.name}</p>)}</div>;
}
Question 52: Explain useTransition Hook
useTransition lets you mark some updates as non-urgent transitions, so they don't block urgent updates.
Example:
import { useState, useTransition } from 'react';
function App() {
const [isPending, startTransition] = useTransition();
const [query, setQuery] = useState('');
const handleChange = (e) => {
setQuery(e.target.value); // Urgent: update input immediately
startTransition(() => {
// Non-urgent: filter results
});
};
return <input value={query} onChange={handleChange} />;
}
Question 53: Hook State Initialization
You can initialize state with a function to compute it lazily (only runs once):
Example:
function App() {
const [data, setData] = useState(() => {
// Expensive calculation here!
const localStorageData = JSON.parse(localStorage.getItem('data'));
return localStorageData || initialData;
});
return <div>{data}</div>;
}
Question 54: useEffect with Empty Dependency Array
Passing an empty array [] as the dependency makes the effect run only once after initial render (like componentDidMount).
Example:
useEffect(() => {
// Run once on mount
fetchInitialData();
const interval = setInterval(doSomething, 1000);
return () => clearInterval(interval); // Cleanup on unmount
}, []);
Question 55: How to update state that depends on previous state
Use a functional update to ensure you always use the latest state.
Example:
setCount(prevCount => prevCount + 1); // Functional update
// Don't do this if count is updated asynchronously!
setCount(count + 1);
Question 56: useEffect Common Mistakes
- Forgetting the dependency array (runs every render)
- Not cleaning up effects (causes memory leaks)
- Putting props/state in the dependency array that don't affect the effect
- Updating state inside the effect without dependencies
Question 57: What are hooks alternatives before v16.8?
Before hooks we used:
- Class components for state/lifecycle
- HOCs (Higher-Order Components)
- Render props
Example (Render Props):
class MouseTracker extends React.Component {
state = { x: 0, y: 0 };
handleMouseMove = (e) => {
this.setState({ x: e.clientX, y: e.clientY });
};
render() {
return (
<div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
{this.props.render(this.state)}
</div>
);
}
}
// Usage
<MouseTracker render={({ x, y }) => (
<h1>Mouse is at {x}, {y}</h1>
)} />
Question 58: useState with arrays/objects
When updating arrays or objects in state, you need to return a new reference!
Array Updates:
const [items, setItems] = useState([]);
// Add
setItems([...items, newItem]);
// Remove
setItems(items.filter(i => i.id !== id));
Object Updates:
const [user, setUser] = useState({ name: '', age: 0 });
// Update
setUser(prev => ({
...prev,
name: 'New Name'
}));
Question 59: useState initial value from props
function UserCard({ initialName }) {
// Initialize state from props
const [name, setName] = useState(initialName);
return <h1>{name}</h1>;
}
Question 60: Are Hooks replacing classes?
No, but they make functional components more powerful and are the recommended approach in modern React. Class components are still supported, though.