React Hooks Interview Questions and Answers
15 questions on useState, useEffect, useRef, useMemo, useCallback, useReducer, context, custom hooks, and the rules of hooks.
1. What are the rules of hooks?
Call hooks only at the top level of a function component or a custom hook, never inside loops, conditions, or nested functions, so React can match hooks by call order between renders. Call them only from React functions. The eslint-plugin-react-hooks lint rules enforce this.
2. How does useState work?
It returns the current state value and a setter. Calling the setter schedules a re-render with the new value. The initial value is used only on the first render; pass a function for expensive initial values (lazy initialization).
const [count, setCount] = useState(0); const [data] = useState(() => computeExpensiveValue());3. How does useEffect work, and what is the dependency array?
useEffect runs side effects after render, such as fetching data, subscriptions, or timers. The dependency array controls when it re-runs: no array means after every render, an empty array means once after mount, and a list means whenever one of those values changes. List every value from the component that the effect uses.
4. Why and how do you clean up effects?
An effect can return a cleanup function, which React runs before re-running the effect and when the component unmounts. Use it to remove event listeners, clear timers, cancel subscriptions, and abort requests, which prevents memory leaks and stale updates.
useEffect(() => { const id = setInterval(tick, 1000); return () => clearInterval(id); }, []);5. How should you fetch data in a component?
In client components, fetch inside useEffect with an abort signal or an ignore flag to avoid setting state after unmount, and track loading and error states. In practice, use a data library such as TanStack Query or SWR for caching, retries, and deduplication, or fetch on the server with a framework that supports Server Components. Avoid fetching data in the render phase directly.
6. What is useRef used for?
useRef returns a mutable object whose current property persists across renders without causing a re-render when changed. Use it to access DOM elements (focus an input), and to keep values such as timer ids or the previous value of a prop.
const inputRef = useRef(null); return <input ref={inputRef} onFocus={() => console.log(inputRef.current.value)} />;7. What is the difference between useMemo and useCallback?
useMemo caches the result of a calculation between renders, and useCallback caches a function definition. Both take a dependency array. They are useful for expensive calculations and for keeping stable references passed to memoized children or used as effect dependencies. Do not add them everywhere: measure first, because they have their own cost.
8. What does React.memo do?
It wraps a component so React skips re-rendering it when its props are shallowly equal to the previous props. It only helps if the parent keeps passing stable references (so memoize object and function props with useMemo or useCallback). The React Compiler, an optional build step, can apply this kind of memoization automatically.
9. When would you use useReducer instead of useState?
When state has several related values or complex transitions, or when the next state depends on actions. A reducer is a pure function (state, action) that returns new state, which centralizes update logic and is easy to test.
function reducer(state, action) { switch (action.type) { case 'add': return { items: [...state.items, action.item] }; case 'clear': return { items: [] }; default: return state; } } const [state, dispatch] = useReducer(reducer, { items: [] });10. How does the Context API work, and what are its drawbacks?
createContext defines a context, a Provider supplies a value to its subtree, and useContext reads it. Every component that reads a context re-renders when the provided value changes, so putting rapidly changing data in one big context can cause wide re-renders. Split contexts, memoize the value, or use a state library for frequently changing state.
11. What is a custom hook?
A function whose name starts with use and that calls other hooks, to reuse stateful logic across components without changing the component hierarchy. Each call gets its own independent state.
function useLocalStorage(key, initial) { const [value, setValue] = useState(() => { const saved = localStorage.getItem(key); return saved ? JSON.parse(saved) : initial; }); useEffect(() => { localStorage.setItem(key, JSON.stringify(value)); }, [key, value]); return [value, setValue]; }12. What is the difference between useEffect and useLayoutEffect?
useEffect runs after the browser has painted, so it does not block the screen. useLayoutEffect runs synchronously after DOM changes but before painting, which is for measuring layout and avoiding visual flicker. Prefer useEffect unless you must measure or mutate the DOM before paint.
13. Why does an effect run twice in development?
In StrictMode, React intentionally mounts, unmounts, and remounts components in development to check that effects clean up properly. If doubling the effect breaks your code, the effect is missing a cleanup or is doing something that should not be an effect. It does not happen in production.
14. What new hooks and features came with React 19?
React 19 added Actions for handling async form submissions, with the hooks useActionState, useFormStatus, and useOptimistic; the use API to read a promise or context during render; ref as a regular prop (so forwardRef is mostly unnecessary); and improved support for document metadata and Server Components. Check the official release notes for details of your version.
Interview Tips
- Always explain the dependency array in terms of values from the component scope.
- Know why a bug happens, such as a stale closure, rather than just the fix.
- Mention accessibility and testing when you describe a component you built.