React Hooks Interview Questions & Answers 2026
- Authors

- Name
- Geeks Kai
- @KaiGeeks

These 10 React Hooks questions focus on choosing state, Effects, refs and memoization for a specific component. Use the subscription and form examples to explain cleanup, dependencies and state ownership; the answers distinguish complete modules from fragments.
Version scope: React 19.3.0. Complete local modules are labeled by filename; short fragments require their stated surrounding bindings. Effects, memoization, and compiler optimizations have explicit boundaries. For state and props prerequisites, see Core React.
This section focuses on React Hooks interview questions, covering useState, useEffect, useCallback, useMemo, useReducer, and custom hooks. Understanding hooks is crucial for modern React development.
Hooks let function components use state, context, refs, and other React features. Custom Hooks reuse stateful logic without requiring a class. Existing classes remain supported; Effects describe synchronization with external systems rather than a one-to-one replacement for every lifecycle method.
Call ordinary Hooks such as useState and useEffect at the top level of a function component or custom Hook, before conditional returns. Do not call them from event handlers, loops, or ordinary helper functions. Custom Hook names start with use so tooling can check their usage.
React 19's use API is a documented exception: it may be called in conditions and loops, but still only while rendering a component or Hook. That exception does not make conditional useState calls valid.
useEffect and useLayoutEffect in React?Both Hooks synchronize after a commit, but they have different scheduling constraints. useLayoutEffect runs before the browser repaints and blocks repaint while its work and scheduled updates complete; reserve it for layout measurement that must happen before display. useEffect usually lets the browser paint first for non-interaction work, but React may run it before paint in interaction-related cases. It is not an unconditional after-paint guarantee. Neither Effect runs during server rendering.
import { useEffect, useLayoutEffect, useRef } from "react"
function MeasurementExample() {
const elementRef = useRef(null)
useLayoutEffect(() => {
console.log("Committed element width:", elementRef.current.offsetWidth)
}, [])
useEffect(() => {
console.log("Passive Effect setup; exact paint ordering is not guaranteed")
}, [])
return <div ref={elementRef}>Hello</div>
}
useEffect affect?The dependency list contains every reactive value used by the setup, including relevant props, state, and functions declared in the component. React compares each dependency with Object.is. With no list, setup runs after each commit; an empty list has no dependency-driven rerun, but does not promise exactly one setup for the application's lifetime.
When a dependency changes, React runs the previous cleanup before the new setup. It runs cleanup when the component unmounts. Root StrictMode adds a development setup/cleanup check; a StrictMode subtree has a different initial-mount Effect boundary. Do not remove StrictMode to hide missing cleanup.
This complete local example makes the subscription and its cleanup observable. Keep the source object stable until you intend to switch subscriptions. The React state setter has a stable identity and need not be included in the dependency list.
// file: message-feed.jsx
import { useEffect, useState } from "react"
export function createMessageSource(initialMessage) {
let currentMessage = initialMessage
const listeners = new Set()
return {
subscribe(listener) {
listeners.add(listener)
listener(currentMessage)
return () => listeners.delete(listener)
},
publish(message) {
currentMessage = message
for (const listener of listeners) {
listener(message)
}
},
getSubscriberCount() {
return listeners.size
},
}
}
export function MessageFeed({ source }) {
const [message, setMessage] = useState("")
useEffect(() => {
// Each source supplies a current string and returns its unsubscribe function.
const unsubscribe = source.subscribe(setMessage)
return unsubscribe
}, [source])
return <output>{message}</output>
}
useRef hook in React and when should it be used?The useRef hook creates a mutable object that persists through renders, allowing direct access to DOM elements, storing mutable values without causing re-renders, and maintaining references to values.
For instance, useRef can be utilized to focus on an input element:
import React, { useRef, useEffect } from "react"
function TextInputWithFocusButton() {
const inputEl = useRef(null)
useEffect(() => {
inputEl.current.focus()
}, [])
return <input ref={inputEl} type="text" />
}
Common use cases:
useCallback hook in React and when should it be used?useCallback caches the returned function reference while its dependencies compare equal. The function expression is still created during rendering; React may return the previously cached function instead. It does not make the callback result a cache or guarantee that a child never renders.
Use it when a stable reference helps an explicitly memoized child or a dependency-sensitive API, after identifying a meaningful cost. Include all reactive values the callback uses. The following is a signature illustration inside a component where submit, productId, and quantity are already defined:
const handleSubmit = useCallback(() => {
submit({ productId, quantity })
}, [submit, productId, quantity])
React Compiler can reduce the need for manual memoization when it is enabled; installing React alone does not enable that optimization.
useMemo hook in React and when should it be used?useMemo caches a calculation result between renders while dependencies compare equal with Object.is. The calculation must remain pure, and every reactive input it reads belongs in the dependency list. React may discard the cache, so application correctness must not depend on it.
This illustrative fragment belongs inside a component with products and searchText in scope:
const visibleProducts = useMemo(() => {
return products.filter(product => product.name.includes(searchText))
}, [products, searchText])
A small filter may be cheaper than the extra bookkeeping. Measure a production-like interaction before adding a cache; returning a memoized value does not itself prevent every child render.
useReducer hook in React and when should it be used?useReducer centralizes related state transitions in a pure reducer. It is useful when actions describe several related fields or when the update rules benefit from a dedicated, testable function. It is not required merely because the next value depends on the previous value: a useState functional updater handles that too.
The following is a fragment inside a component with reducer and initialState defined:
const [state, dispatch] = useReducer(reducer, initialState)
const increment = () => dispatch({ type: "increment" })
Dispatch from an event handler, not unconditionally during rendering. A custom Hook can share reducer logic, but separate callers do not automatically share the same state.
useId hook in React and when should it be used?useId supplies an ID for accessibility relationships such as a label and input. It stays associated with that component instance across renders. Do not use it for list keys; keys come from the underlying records. Multiple independent React roots should use distinct identifierPrefix values, and server/client prefixes must match during hydration.
import { useId } from "react"
function NameInput() {
const inputId = useId()
return (
<div>
<label htmlFor={inputId}>Name</label>
<input id={inputId} type="text" />
</div>
)
}
A custom Hook starts with use, calls Hooks according to their rules, and returns the state or operations its callers need. It reuses logic; each caller gets its own state unless an external store or Context deliberately shares it.
This complete text-field example extracts the event values before using a functional update, so two queued changes preserve both fields:
// file: use-form.jsx
import { useState } from "react"
export function useForm(initialValues) {
const [formValues, setFormValues] = useState(initialValues)
function handleChange(event) {
const { name, value } = event.target
setFormValues(previousValues => ({ ...previousValues, [name]: value }))
}
return { formValues, handleChange }
}
export function NameForm() {
const { formValues, handleChange } = useForm({ name: "", email: "" })
return (
<label>
Name
<input name="name" value={formValues.name} onChange={handleChange} />
</label>
)
}
This Hook handles string-valued text inputs. Checkboxes, validation, submission, and cross-form synchronization require their own explicit behavior.
Continue your React JS interview questions preparation with these related topics:
Master Core React interview questions covering JSX, Virtual DOM, Components, Props, State, and more. Essential React JS ...
Master React State Management interview questions covering useState, Context API, Redux, and state optimization. Essenti...
Comprehensive React Rendering & Performance interview questions covering Virtual DOM, memoization, code splitting, and o...
Master all aspects of React development
This article is part of our comprehensive React JS interview questions series covering all aspects of React development. Explore all topics: