Data Structures and Algorithms
- Introduction to Data Structures and Algorithms
- Time and Space Complexity Analysis
- Big-O, Big-Theta, and Big-Omega Notations
- Recursion and Backtracking
- Divide and Conquer Algorithm
- Dynamic Programming: Memoization vs. Tabulation
- Greedy Algorithms and Their Use Cases
- Understanding Arrays: Types and Operations
- Linear Search vs. Binary Search
- Sorting Algorithms: Bubble, Insertion, Selection, and Merge Sort
- QuickSort: Explanation and Implementation
- Heap Sort and Its Applications
- Counting Sort, Radix Sort, and Bucket Sort
- Hashing Techniques: Hash Tables and Collisions
- Open Addressing vs. Separate Chaining in Hashing
- DSA Questions for Beginners
- Advanced DSA Questions for Competitive Programming
- Top 10 DSA Questions to Crack Your Next Coding Test
- Top 50 DSA Questions Every Programmer Should Practice
- Top Atlassian DSA Interview Questions
- Top Amazon DSA Interview Questions
- Top Microsoft DSA Interview Questions
- Top Meta (Facebook) DSA Interview Questions
- Netflix DSA Interview Questions and Preparation Guide
- Top 20 DSA Interview Questions You Need to Know
- Top Uber DSA Interview Questions and Solutions
- Google DSA Interview Questions and How to Prepare
- Airbnb DSA Interview Questions and How to Solve Them
- Mobile App DSA Interview Questions and Solutions
DSA Interview Questions
- DSA Questions for Beginners
- Advanced DSA Questions for Competitive Programming
- Top 10 DSA Questions to Crack Your Next Coding Test
- Top 50 DSA Questions Every Programmer Should Practice
- Top Atlassian DSA Interview Questions
- Top Amazon DSA Interview Questions
- Top Microsoft DSA Interview Questions
- Top Meta (Facebook) DSA Interview Questions
- Netflix DSA Interview Questions and Preparation Guide
- Top 20 DSA Interview Questions You Need to Know
- Top Uber DSA Interview Questions and Solutions
- Google DSA Interview Questions and How to Prepare
- Airbnb DSA Interview Questions and How to Solve Them
- Mobile App DSA Interview Questions and Solutions
Data Structures and Algorithms
- Introduction to Data Structures and Algorithms
- Time and Space Complexity Analysis
- Big-O, Big-Theta, and Big-Omega Notations
- Recursion and Backtracking
- Divide and Conquer Algorithm
- Dynamic Programming: Memoization vs. Tabulation
- Greedy Algorithms and Their Use Cases
- Understanding Arrays: Types and Operations
- Linear Search vs. Binary Search
- Sorting Algorithms: Bubble, Insertion, Selection, and Merge Sort
- QuickSort: Explanation and Implementation
- Heap Sort and Its Applications
- Counting Sort, Radix Sort, and Bucket Sort
- Hashing Techniques: Hash Tables and Collisions
- Open Addressing vs. Separate Chaining in Hashing
- DSA Questions for Beginners
- Advanced DSA Questions for Competitive Programming
- Top 10 DSA Questions to Crack Your Next Coding Test
- Top 50 DSA Questions Every Programmer Should Practice
- Top Atlassian DSA Interview Questions
- Top Amazon DSA Interview Questions
- Top Microsoft DSA Interview Questions
- Top Meta (Facebook) DSA Interview Questions
- Netflix DSA Interview Questions and Preparation Guide
- Top 20 DSA Interview Questions You Need to Know
- Top Uber DSA Interview Questions and Solutions
- Google DSA Interview Questions and How to Prepare
- Airbnb DSA Interview Questions and How to Solve Them
- Mobile App DSA Interview Questions and Solutions
DSA Interview Questions
- DSA Questions for Beginners
- Advanced DSA Questions for Competitive Programming
- Top 10 DSA Questions to Crack Your Next Coding Test
- Top 50 DSA Questions Every Programmer Should Practice
- Top Atlassian DSA Interview Questions
- Top Amazon DSA Interview Questions
- Top Microsoft DSA Interview Questions
- Top Meta (Facebook) DSA Interview Questions
- Netflix DSA Interview Questions and Preparation Guide
- Top 20 DSA Interview Questions You Need to Know
- Top Uber DSA Interview Questions and Solutions
- Google DSA Interview Questions and How to Prepare
- Airbnb DSA Interview Questions and How to Solve Them
- Mobile App DSA Interview Questions and Solutions
React Hooks Interview Questions: Top 50 Prep Guide
In today’s competitive tech interviews, demonstrating solid mastery of React Hooks can set you apart. If you’d like to receive free course updates and resources to boost your preparation, join our community for exclusive content. This guide covers 50 carefully chosen React Hooks questions, each with clear explanations, examples, and best practices. Whether you’re aiming for an SDE 2 position or a senior frontend engineer role, you’ll gain insights into fundamentals, performance tuning, real-world patterns, and advanced scenarios.
Why React Hooks Matter in Interviews
React Hooks, introduced in React 16.8, enable function components to manage state, side effects, refs, context, and more without classes. Top-tier companies expect candidates to:
- Understand fundamentals: Know how built-in Hooks (useState, useEffect, useRef, etc.) work, their rules, and common pitfalls.
- Design custom Hooks: Extract reusable logic, manage complex state, handle async operations, and ensure cleanup.
- Optimize performance: Use useMemo, useCallback, useTransition, and React Profiler effectively to prevent unnecessary renders.
- Handle real-world scenarios: Data fetching with cancellation, infinite scroll, subscriptions, SSR/Next.js considerations, and accessibility concerns.
- Demonstrate best practices: Correct dependency management, avoiding stale closures, testing Hooks, and balancing readability vs. optimization.
Building a strong foundation in Hooks not only helps you answer interview questions but also leads to writing cleaner, more scalable code. For hands-on practice building React applications, consider exploring our Web Development course to reinforce concepts with real projects.
Basic React Hooks Questions
1. What are React Hooks and why were they introduced?
React Hooks are functions that let you “hook into” React features in function components. Core built-in Hooks include useState, useEffect, useRef, useContext, etc. They were introduced to:
- Eliminate the need for class components for stateful logic.
- Enable reuse of stateful logic via custom Hooks instead of patterns like higher-order components (HOCs) or render props, reducing wrapper hell.
- Simplify component code by avoiding this, binding, and class lifecycle methods.
- Encourage a more functional style and make code easier to test and share.
2. What are the Rules of Hooks?
React enforces two main rules:
- Only call Hooks at the top level: Don’t call Hooks inside loops, conditions, or nested functions. Ensures React can track Hook calls order across renders.
- Only call Hooks from React function components or custom Hooks: Avoid calling Hooks from regular JavaScript functions. Ensures Hooks are used in the React rendering context.
Violating these leads to errors or unpredictable behavior. ESLint plugin eslint-plugin-react-hooks helps catch missing dependencies and invalid Hook usage.
3. How does useState work internally?
- State persistence: React keeps a linked list (or array) of Hook states for each component. On re-render, useState retrieves the stored state by index/order.
- Setter function: Calling the setter enqueues a state update; React schedules a re-render. React may batch multiple updates for performance.
- Functional updates: If the new state depends on previous state, pass a function to the setter: setCount(prev => prev + 1) to avoid stale closures in async contexts.
Initial state: The initial value parameter is used only on the first render. For expensive initialization, pass a function: useState(() => expensiveComputation()).

4. How is useEffect different from lifecycle methods in class components?
- Timing: useEffect runs after rendering and after painting to the screen by default. Analogous to combining componentDidMount, componentDidUpdate, and cleanup like componentWillUnmount.
- Cleanup: Returning a function in useEffect runs before unmount or before re-running the effect due to dependency changes.
- Dependency array: Controls when the effect runs:
- Empty array []: run once after mount.
- Specified dependencies [dep1, dep2]: run after mount and whenever any dependency changes.
- Omitted array: run after every render (rarely recommended).
- In class components, you needed separate methods; useEffect consolidates them in one API.
5. What is the dependency array in useEffect?
The dependency array is the second argument to useEffect: useEffect(() => { /* effect */ }, [dep1, dep2]). React compares dependencies using the Object.is an algorithm for each render:
- If any dependency changed since the last render, re-run the effect (cleanup first, if provided).
- If an empty array [], the effect runs only once after mount (and cleanup on unmount).
- If omitted, runs after every render.
Correct dependencies ensure effects run when expected without stale data or unnecessary runs.
6. What happens if you omit the dependency array in useEffect?
Omitting the dependency array means the effect runs after every render. Consequences:
- Potential performance issues due to repeated side effects.
- Risk of infinite loops if the effect updates the state that triggers re-render.
- Rarely used except for debugging or very specific scenarios.
Better to specify dependencies explicitly or use an empty array for “run once” behavior.
7. How do you update the state based on the previous state using useState?
Use the functional updater form:
setCount(prevCount => prevCount + 1);
This ensures the update uses the latest state, avoiding stale closures when multiple updates are enqueued or in asynchronous callbacks.
8. When should you use useRef over useState?
useRef creates a mutable object with a .current property that persists across renders without triggering re-renders when mutated. Use cases:
- Storing references to DOM elements: const inputRef = useRef(null);
- Keeping mutable values (e.g., timer IDs, previous props) without causing re-render.
- Avoid re-renders for values that change but don’t affect the UI.
useState should be used when changes need to trigger a re-render.
9. What’s the difference between useEffect and useLayoutEffect?
- useEffect: Runs asynchronously after the browser paints. Non-blocking to painting; suitable for data fetching, subscriptions, logging.
- useLayoutEffect: Runs synchronously after DOM mutations but before paint. Blocks painting until cleanup and effect run. Use for reading layout (e.g., measuring DOM nodes) and synchronously making DOM changes to avoid flicker.
Prefer useEffect unless you need to measure or adjust layout before the user sees it.
10. How do you avoid stale closures in Hooks?
Stale closures occur when an effect or callback captures outdated variables. Strategies:
- Dependency arrays: Include all variables used inside useEffect or useCallback so they capture fresh values.
- Functional updates: For state setters, use setState(prev => …) to always work with latest state.
- Refs: Store mutable values in useRef and read .current in effects/callbacks to access latest without re-running effect.
- Memoization patterns: Ensure dependencies of useCallback or useMemo include all referenced values to update as needed.
- Lint rules: Use ESLint Hooks rules to catch missing dependencies.
Intermediate Hook Concepts
11. What is useCallback and when should you use it?
useCallback(fn, deps) returns a memoized version of the callback that only changes if dependencies change. Use cases:
- Prevent child components from re-rendering when passed a function prop, if the function identity stays stable.
- Useful with React.memo or optimization in large component trees.
Caveats: - Overuse can add complexity; only use when actual performance issues arise (profile first).
- Dependencies must include all external values used inside the callback.
12. How does useMemo help with performance?
useMemo(() => computeExpensiveValue(a, b), [a, b]) memoizes the result, re-computing only when dependencies change. Use to:
- Avoid expensive calculations on every render.
- Prevent creating new object/array references when unchanged, useful for prop comparisons.
Caveats: - Memoization has overhead; apply only when computation cost or referential equality matters.
- Dependencies must be accurate to avoid stale results.
13. How do you create a custom Hook?
Custom Hooks are JavaScript functions whose names start with use, and may call other Hooks. Steps:
- Identify reusable logic (e.g., data fetching, form handling, subscriptions).
Create a function:
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let isMounted = true;
setLoading(true);
fetch(url)
.then(res => res.json())
.then(json => {
if (isMounted) {
setData(json);
setLoading(false);
}
})
.catch(err => {
if (isMounted) {
setError(err);
setLoading(false);
}
});
return () => {
isMounted = false;
};
}, [url]);
return { data, loading, error };
}
14. What are some best practices when writing custom Hooks?
- Naming: Always start with use.
- Single responsibility: Each custom Hook manages a specific piece of logic (e.g., useDebounce, useLocalStorage, useAuth).
- Dependencies: Declare all dependencies in internal useEffect or useCallback arrays.
- Cleanup: Return cleanup functions to avoid leaks (e.g., unsubscribing, aborting fetch).
- Return stable references: Memoize returned functions/objects if consumers rely on referential equality.
- Type safety: In TypeScript projects, type inputs, return values, and internal state.
- Testing: Write unit tests for custom Hooks using testing utilities like React Testing Library’s renderHook.
- Documentation: Describe inputs, outputs, side effects, and expected usage.
15. When would you use useReducer over useState?
- Complex state logic: When state updates involve multiple sub-values or complex transitions (e.g., a form with many fields, toggle logic, multi-step workflows).
- Predictable updates: Reducer centralizes update logic in a pure function, easier to test.
Performance: Passing dispatch down via context can avoid prop drilling; ensures updates logic lives in one place.
Example:
function formReducer(state, action) {
switch (action.type) {
case 'SET_FIELD': return { ...state, [action.field]: action.value };
case 'RESET': return initialState;
default: throw new Error();
}
}
const [state, dispatch] = useReducer(formReducer, initialState);
16. What is the role of useContext in state management?
useContext(MyContext) lets function components consume context values. Use cases:
- Share global or app-wide state (e.g., theme, auth) without prop drilling.
- Combined with useReducer, context can provide a Redux-like pattern: a context provider holds state and dispatch, consumers can useContext to read state or dispatch actions.
Pitfalls: - Changing context value triggers all consumers to re-render; mitigate via memoizing context value or splitting contexts.
17. How do you clean up side effects in useEffect?
Return a cleanup function from the effect:
useEffect(() => {
const id = setInterval(() => { /* do something */ }, 1000);
return () => clearInterval(id);
}, []);
Cleanup runs:
- Before the component unmounts.
- Before re-running the effect due to changed dependencies.
Proper cleanup prevents memory leaks, stale event listeners, or updating state on unmounted components.
18. How do you test components that use Hooks?
- React Testing Library: Render component and assert behavior (state changes, DOM updates).
- Mocking async behavior: Use jest.useFakeTimers() for timer-based effects; mock fetch or other APIs.
- Testing custom Hooks directly: Use @testing-library/react-hooks or React Testing Library’s renderHook utility to call the Hook in isolation, assert state transitions.
- Cleanup between tests: Ensure effects are cleaned up; testing-library handles unmount cleanup automatically when using cleanup.
- Edge cases: Simulate rapid prop changes to test cleanup logic in effects.
19. How do you prevent unnecessary re-renders in components using Hooks?
- Memoize callbacks/values: Use useCallback and useMemo when passing props to memoized child components.
- React.memo: Wrap function components to avoid re-render if props don’t change.
- Split context: If using context, split values so updates only affect relevant consumers.
- Avoid inline objects/arrays: Inline definitions cause new references each render; memoize or hoist constants.
- Profile: Use React DevTools Profiler to identify unnecessary renders before optimizing.
- Batch updates: React batches state updates by default; avoid forcing extra renders.
20. How do you debounce a value or function using Hooks?
Implement a useDebounce custom Hook:
function useDebounce(value, delay) {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const handler = setTimeout(() => setDebounced(value), delay);
return () => clearTimeout(handler);
}, [value, delay]);
return debounced;
}
Use in component:
const [searchTerm, setSearchTerm] = useState('');
const debouncedTerm = useDebounce(searchTerm, 500);
useEffect(() => {
// fetch results using debouncedTerm
}, [debouncedTerm]);
Debouncing prevents rapid state changes or API calls, optimizing performance.
Advanced Hook Scenarios
21. How do you handle race conditions in useEffect?
Race conditions occur when multiple async calls complete out of order, leading to stale state. Strategies:
AbortController: For fetch requests, use AbortController to cancel previous request on new effect run:
useEffect(() => {
const controller = new AbortController();
fetch(url, { signal: controller.signal })
.then(...)
.catch(err => {
if (err.name !== 'AbortError') { /* handle */ }
});
return () => controller.abort();
}, [url]);
Sequence tracking: Use a ref counter:
const seq = useRef(0);
useEffect(() => {
seq.current += 1;
const current = seq.current;
fetch(url).then(res => {
if (seq.current === current) { setData(res); }
});
}, [url]);
- Libraries: Use React Query or SWR which handle caching, deduplication, cancellation.
22. How do you cancel a fetch request inside a Hook?
Use AbortController in useEffect cleanup:
useEffect(() => {
const controller = new AbortController();
fetch(url, { signal: controller.signal })
.then(...)
.catch(err => {
if (err.name === 'AbortError') {
// request was cancelled
} else {
// handle error
}
});
return () => controller.abort();
}, [url]);
Ensures no state updates from stale requests after unmount or URL change.
23. How does useImperativeHandle work with forwardRef?
useImperativeHandle(ref, createHandle, [deps]) customizes the instance value exposed to parent when using ref on a function component. Steps:
- Wrap component with forwardRef.
- Inside, call useImperativeHandle(ref, () => ({ customMethod, … })).
- Parent can call ref.current.customMethod().
Use case: Expose imperative methods (e.g., focus, scrollTo) from a custom input component. Ensures encapsulation, exposing only specific methods.

24. What is useDebugValue and when should you use it?
useDebugValue(value) displays a label for custom Hooks in React DevTools to help debugging. For example:
function useAuth() {
const [user, setUser] = useState(null);
// ...
useDebugValue(user ? 'LoggedIn' : 'LoggedOut');
return user;
Useful in libraries or complex custom Hooks to indicate internal state at a glance.
25. How would you implement usePrevious custom Hook?
Track previous value across renders:
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
Before effect runs, ref.current holds previous value; initial previous is undefined. Useful for comparing prop or state changes.
26. How do you share logic between components using Hooks?
Extract reusable behavior into custom Hooks. For example:
- Data fetching: useFetch, useAxios.
- Form handling: useForm, handling validation, state updates.
- Subscriptions: useEventListener, useWebSocket.
- Animations: useAnimationFrame, useTransition.
Each custom Hook encapsulates state, effects, and returns necessary values or functions. Encourages DRY code and easier testing.
27. How do you manage complex form state with Hooks?
useReducer: Centralize form state and validation logic:
function formReducer(state, action) { /* manage fields, errors */ }
const [state, dispatch] = useReducer(formReducer, initialFormState);
- Custom Hooks: useForm returning { values, errors, handleChange, handleSubmit }.
- Validation: Perform synchronous validation on change or async (e.g., checking username availability) in effects with cancellation.
- Third-party libraries: Libraries like Formik or React Hook Form use Hooks internally; understand underlying patterns.
- Performance: Avoid re-renders on unrelated field changes by splitting form sections or using uncontrolled inputs with refs when appropriate.
28. How does Hooks-based state management compare to Redux?
- Local vs. global: Hooks (useState, useReducer + context) handle local or simple global state. Redux suits large-scale or complex shared state with middleware, time-travel debugging.
- Boilerplate: Hooks approach often has less boilerplate; Redux provides structured patterns for large apps.
- Performance: Both can be optimized; context updates can cause broad re-renders unless value is memoized or contexts are split.
- Ecosystem: Redux ecosystem includes devtools, middleware, persistence; Hooks + context may need custom solutions.
In interviews, explain when to choose one over the other based on app complexity, team conventions, and performance requirements.
29. How do Hooks behave in Server-Side Rendering (SSR)?
- No effects on server: useEffect and useLayoutEffect do not run on the server. Code relying on window or DOM must be guarded.
- Data fetching: For SSR frameworks like Next.js, data fetching often happens in special functions (getServerSideProps) rather than in useEffect.
- Hydration: Ensure initial render matches server HTML to avoid hydration mismatches.
- Custom Hooks: Might need to detect execution environment (e.g., typeof window !== ‘undefined’) before calling browser-only APIs.
- useLayoutEffect warning: React warns when useLayoutEffect runs on server; use useEffect or conditional logic.
30. How can you persist values between renders without re-rendering?
Use useRef for mutable storage that survives across renders but does not trigger re-render on change:
- Example: Track previous prop/state, store timers, or counters.
Alternatively, store in external modules or browser storage (localStorage) via custom Hooks (useLocalStorage), but reading/writing localStorage may cause side effects and re-renders if state is updated.
Performance Optimization with Hooks
31. How do you profile a component that uses Hooks?
- React DevTools Profiler: Record interactions to see render times. Identify which components render frequently and why.
- Why-render tools: Use custom logs or React DevTools highlight updates.
- Benchmarking: Console.time blocks around expensive calculations.
- Network throttling: Simulate slow connections for data-fetching Hooks.
- Measure impact: Introduce/removing useMemo or useCallback to observe performance changes.
- Analyze bundle size: Ensure Hooks or libraries do not bloat the bundle.
32. How can Hooks lead to performance issues if used incorrectly?
- Missing dependencies: Effects re-run unnecessarily or capture stale values, causing repeated work.
- Overuse of memoization: Unnecessary useMemo/useCallback adds overhead if computation or identity stability is trivial.
- Context re-renders: Providing a new object/array inline to context value causes all consumers to re-render.
- Expensive calculations in render: Doing heavy computation directly in body without useMemo.
- Infinite loops: Poor dependency arrays in useEffect causing repeated state updates.
- Large lists: Rendering large arrays without virtualization or memoization.
33. When should you use React.memo with Hooks?
Wrap a function component to prevent re-render if props haven’t changed (shallow comparison). Use when:
- Child component renders frequently due to parent state changes but props remain identical.
- Combined with stable callback and value references via useCallback/useMemo.
Avoid premature optimization; profile first to confirm re-render is a performance bottleneck.
34. How do you optimize re-renders in context-consuming components?
Memoize context value: Wrap provider value in useMemo:
const value = useMemo(() => ({ state, dispatch }), [state, dispatch]);
<MyContext.Provider value={value}>…
- Split contexts: Separate independent pieces of global state into multiple contexts so updates affect only concerned consumers.
- Selector patterns: Some libraries allow subscribing to specific slices of context to avoid full re-renders.
- Local state: Lift only truly shared state to context; keep component-specific state local.
35. How do you throttle or debounce in a custom Hook?
- Debounce: As in [Question 20], use setTimeout and clearTimeout in useEffect.
Throttle: Use useRef to track last execution time:
function useThrottle(fn, delay) {
const lastCall = useRef(0);
return useCallback((...args) => {
const now = Date.now();
if (now - lastCall.current >= delay) {
lastCall.current = now;
fn(...args);
}
}, [fn, delay]);
}
- Use in effects or event handlers to limit frequency of expensive operations (scroll, resize, API calls).
36. How do you use useTransition to improve UX?
useTransition (React 18+) marks state updates as non-urgent. Example:
function handleSearch(input) {
setQuery(input); // urgent for input display
startTransition(() => {
setFilteredData(heavyFilter(data, input)); // non-urgent rendering
});
}
During transition, React can show a pending state (e.g., spinner) without blocking input responsiveness. Use for expensive renders to keep UI fluid.
37. What is useDeferredValue and when should you use it?
useDeferredValue(value) returns a deferred version of a rapidly changing value, allowing UI to remain responsive. Useful when:
- Filtering large lists: use deferred input to update list rendering less urgently than input state.
- Combined with useTransition for smoother updates.
Helps avoid janky rendering on frequent input changes.
38. How do you manage global state using Hooks only?
- Context + useReducer: Create a context provider with useReducer for state and dispatch; consumers use useContext.
- Custom subscription pattern: Use an event emitter or external store with Hooks subscribing to updates.
- Limit scope: Only share truly global state; isolate concerns to avoid broad re-renders.
- Compare with libraries: For large-scale state (caching, middleware), consider libraries (Redux, Zustand). In interviews, explain trade-offs.
39. How does batching work in React with Hooks?
React automatically batches state updates in event handlers and lifecycle/updater functions in React 18+. Multiple setState calls within the same event are grouped into a single render. For async callbacks (e.g., promises, setTimeout), React 18+ also batches by default. Batching reduces unnecessary renders, improving performance. Understand how batching interacts with Hooks: multiple setState calls in an effect or callback result in one re-render.
40. How do Hooks behave in React’s concurrent mode?
- Concurrent rendering: React may pause, restart, or abort renders to prioritize urgent updates. Hooks code must be pure and free of side effects in render phase.
- useTransition, useDeferredValue: Leverage concurrent features to mark non-urgent updates.

- Avoid side effects during render: Effects (useEffect) run after commit; ensure heavy computations are safe to be re-run if React discards intermediate renders.
- Debugging: Profile under concurrency; ensure components remain responsive and consistent when renders are interrupted.
Real-World Hooks Application
41. How do you fetch paginated data with Hooks?
Implement a custom Hook usePaginatedFetch:
- State: page, data, loading, error, hasMore.
- Effect: On [url, page], fetch data, append to existing list.
- Cancellation: Use AbortController or sequence tracking to avoid stale results.
Load more: Expose a function loadNextPage to increment page.
Example:
function usePaginatedFetch(baseUrl) {
const [page, setPage] = useState(1);
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [hasMore, setHasMore] = useState(true);
useEffect(() => {
let isMounted = true;
const controller = new AbortController();
setLoading(true);
fetch(`${baseUrl}?page=${page}`, { signal: controller.signal })
.then(res => res.json())
.then(json => {
if (isMounted) {
setItems(prev => [...prev, ...json.items]);
setHasMore(json.items.length > 0);
setLoading(false);
}
})
.catch(err => {
if (isMounted && err.name !== 'AbortError') {
setError(err);
setLoading(false);
}
});
return () => {
isMounted = false;
controller.abort();
};
}, [baseUrl, page]);
const loadNextPage = useCallback(() => {
if (hasMore && !loading) setPage(p => p + 1);
}, [hasMore, loading]);
return { items, loading, error, hasMore, loadNextPage };
}
Use infinite scroll or “Load More” button tied to loadNextPage.
For an example implementation and practice, browse our DSA course to strengthen algorithmic thinking behind pagination logic.
42. How would you handle socket connections with Hooks?
- Custom Hook useWebSocket:
- Initialize WebSocket in useEffect on mount.
- Store socket instance in useRef.
- Listen to messages: update state via useState or pass to callback.
Cleanup: close socket on unmount.
Example:
function useWebSocket(url, onMessage) {
const socketRef = useRef(null);
useEffect(() => {
const socket = new WebSocket(url);
socketRef.current = socket;
socket.onmessage = event => onMessage(JSON.parse(event.data));
// handle onopen, onerror as needed
return () => {
socket.close();
};
}, [url, onMessage]);
const sendMessage = useCallback(msg => {
if (socketRef.current?.readyState === WebSocket.OPEN) {
socketRef.current.send(JSON.stringify(msg));
}
}, []);
return { sendMessage };
}
Ensure reconnection logic or error handling based on requirements.
43. How do you structure Hooks in a large codebase?
- Folder conventions: Place custom Hooks in a hooks/ directory, grouped by domain (e.g., hooks/useAuth.js, hooks/useCart.js).
- Consistent naming: useXxx.
- Shared utilities: Common logic (e.g., API clients) extracted into modules and used in Hooks.
- Testing: Each Hook has unit tests verifying behavior under various scenarios.
- Documentation: Document inputs, outputs, side effects, and dependencies.
- Performance considerations: Monitor when combining multiple Hooks; ensure minimal re-renders.
- Versioning: For shared component libraries, manage Hook versions carefully to avoid mismatched React versions.
44. How do you integrate third-party libraries (like RxJS) with Hooks?
- Subscriptions in useEffect: Subscribe on mount, update state in next callback, cleanup subscription on unmount.
Example:
function useObservable(observable$, initialValue) {
const [value, setValue] = useState(initialValue);
useEffect(() => {
const subscription = observable$.subscribe(val => {
setValue(val);
});
return () => subscription.unsubscribe();
}, [observable$]);
return value;
}
- Ensure stable references: Memoize observables or recreate when truly needed.
- Error handling: Handle errors in subscriptions, possibly expose error state.
- Performance: Avoid too frequent state updates; throttle or debounce inside observables if needed.
45. How would you handle accessibility (focus, keyboard navigation) with Hooks?
- Refs for focus management: Use useRef to reference DOM nodes and call .focus() imperatively within useEffect or event handlers.
- Custom Hooks: useFocusTrap, useKeyboardNavigation to encapsulate logic for modal dialogs or list navigation.
- ARIA attributes: Manage ARIA roles and attributes in JSX; update attributes based on state.
- Event listeners: Use useEffect to add keyboard event listeners (e.g., Escape key to close modal), with cleanup.
- Testing: Test accessibility behavior manually and with automated tools (e.g., axe). In interviews, mention how Hooks facilitate encapsulated accessibility logic.
46. What are the common pitfalls of using Hooks and how to avoid them?
- Missing dependencies: Effects not updated when dependencies change → stale data or bugs. Use ESLint Hooks rules.
- Over-memoization: Unnecessary useMemo/useCallback adds complexity without benefit. Profile first.
- Infinite loops: useEffect updates state without correct dependency checks leads to continuous re-renders.
- useLayoutEffect on server: Causes warnings in SSR; guard or switch to useEffect.
- State updates on unmounted components: Async operations finishing after unmount; handle via AbortController or isMounted flags.
- Context misuse: Passing new object/array inline to provider triggers excessive re-renders; memoize or split context.
- Incorrect ref usage: Mutating useRef without understanding that updates don’t trigger renders.
Avoid pitfalls through linting, profiling, and thorough testing.
47. How do you test async logic in custom Hooks?
- renderHook utility: From React Testing Library or @testing-library/react-hooks.
- Mock APIs: Mock fetch or axios calls, simulate resolved/rejected promises.
- Fake timers: Use jest.useFakeTimers() to simulate timeouts in debouncing or polling Hooks; advance timers to trigger behavior.
- Cleanup: Ensure cleanup functions run correctly by unmounting the Hook and verifying no state updates occur after unmount.
- Edge cases: Test cancellation logic (e.g., aborting fetch), error states, retry mechanisms.
48. How do you use Hooks in combination with Suspense?
- Data fetching libraries: Libraries like React Query or Relay integrate with Suspense by throwing promises in render until data is ready.
- Custom approach: Advanced patterns may wrap fetch in resource that throws a promise; use useMemo or custom resource Hook.
- Fallback UI: Use <Suspense fallback={<Spinner />}> around components that suspend.

- Server Components: In React Server Components, data fetching may suspend on server; understand how Hooks differ between client and server.
- Error boundaries: Combine with Error Boundaries to catch thrown errors or rejections.
49. What Hook would you use to track window size or scroll position?
useWindowSize:
function useWindowSize() {
const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight });
useEffect(() => {
function handleResize() {
setSize({ width: window.innerWidth, height: window.innerHeight });
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return size;
}
- useScrollPosition: Listen to scroll events via useEffect, update state or call a callback. Debounce or throttle updates to avoid performance issues.
- Ensure cleanup, performance optimizations (throttle), and SSR guard (if (typeof window !== ‘undefined’)).
50. How would you build an infinite scroll component with Hooks?
Combine pagination and scroll event detection:
- State: Track items, page, loading, hasMore.
- Effect for data fetch: As described in question 41 (paginated fetch).
- Scroll listener: In useEffect, add scroll event listener to window or a container; determine when user nears bottom; debounce/throttle listener.
- Load more: Call loadNextPage from custom Hook.
- Cleanup: Remove listener on unmount.
UX: Show loading spinner, handle errors, provide fallback “Load More” button if preferred.
Example:
function useInfiniteScroll(fetchFn) {
const [page, setPage] = useState(1);
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(false);
const [hasMore, setHasMore] = useState(true);
useEffect(() => {
let isMounted = true;
setLoading(true);
fetchFn(page)
.then(newItems => {
if (isMounted) {
setItems(prev => [...prev, ...newItems]);
setHasMore(newItems.length > 0);
setLoading(false);
}
})
.catch(() => {
if (isMounted) setLoading(false);
});
return () => { isMounted = false; };
}, [page, fetchFn]);
useEffect(() => {
function handleScroll() {
if (loading || !hasMore) return;
const scrollPosition = window.innerHeight + document.documentElement.scrollTop;
const threshold = document.documentElement.offsetHeight - 100;
if (scrollPosition >= threshold) {
setPage(p => p + 1);
}
}
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, [loading, hasMore]);
return { items, loading, hasMore };
}
Use inside component: call useInfiniteScroll with appropriate fetch function; render items and loading indicator.
For deeper algorithmic patterns behind efficient lists, consider our Design + DSA Combined course.
Next Steps
- Practice coding: Write and refactor components using Hooks; build custom Hooks for real scenarios.
- Profile and optimize: Use React DevTools Profiler on sample apps to see the impact of memoization and batching.
- Test extensively: Implement unit tests for custom Hooks, simulate async flows, and verify cleanup logic.
- Mock interviews: Explain concepts out loud, whiteboard code patterns, and get feedback.
- Stay updated: Follow React release notes (e.g., new concurrent features) and official documentation to reference the latest best practices.
By articulating clear, concise answers with examples and trade-offs, you’ll demonstrate expertise and readiness for technical interviews at Google, Amazon, Netflix, Microsoft, Atlassian, and beyond. Good luck on your React Hooks interview preparation journey!
FAQs
What are React Hooks?
React Hooks are functions (e.g., useState, useEffect) that let you use state and lifecycle features in function components without classes.
Why prepare React Hooks interview questions?
Top companies test deep understanding of Hooks for building scalable, maintainable UIs. Practicing shows you can handle real-world scenarios.
How to demonstrate useEffect knowledge in an interview?
Explain dependency arrays, cleanup functions, and differences from class lifecycle methods. Mention avoiding stale closures and infinite loops.
What custom Hook examples should I know?
Be ready to discuss usePrevious, useFetch, useDebounce, or form-handling hooks. Show how you manage state, effects, cleanup, and dependencies.
How do I explain performance optimization with Hooks?
Talk about useMemo, useCallback, React.memo, and profiling with React DevTools. Illustrate when memoization helps and when it’s unnecessary.
How to answer questions about async logic in Hooks?
Describe using useEffect with AbortController, sequence tracking to prevent race conditions, and cleanup to avoid state updates after unmount.

DSA, High & Low Level System Designs
- 85+ Live Classes & Recordings
- 24*7 Live Doubt Support
- 400+ DSA Practice Questions
- Comprehensive Notes
- HackerRank Tests & Quizzes
- Topic-wise Quizzes
- Case Studies
- Access to Global Peer Community
Buy for 60% OFF
₹25,000.00 ₹9,999.00
Accelerate your Path to a Product based Career
Boost your career or get hired at top product-based companies by joining our expertly crafted courses. Gain practical skills and real-world knowledge to help you succeed.

Essentials of Machine Learning and Artificial Intelligence
- 65+ Live Classes & Recordings
- 24*7 Live Doubt Support
- 22+ Hands-on Live Projects & Deployments
- Comprehensive Notes
- Topic-wise Quizzes
- Case Studies
- Access to Global Peer Community
- Interview Prep Material
Buy for 65% OFF
₹20,000.00 ₹6,999.00

Fast-Track to Full Spectrum Software Engineering
- 120+ Live Classes & Recordings
- 24*7 Live Doubt Support
- 400+ DSA Practice Questions
- Comprehensive Notes
- HackerRank Tests & Quizzes
- 12+ live Projects & Deployments
- Case Studies
- Access to Global Peer Community
Buy for 57% OFF
₹35,000.00 ₹14,999.00

DSA, High & Low Level System Designs
- 85+ Live Classes & Recordings
- 24*7 Live Doubt Support
- 400+ DSA Practice Questions
- Comprehensive Notes
- HackerRank Tests & Quizzes
- Topic-wise Quizzes
- Case Studies
- Access to Global Peer Community
Buy for 60% OFF
₹25,000.00 ₹9,999.00

Low & High Level System Design
- 20+ Live Classes & Recordings
- 24*7 Live Doubt Support
- 400+ DSA Practice Questions
- Comprehensive Notes
- HackerRank Tests
- Topic-wise Quizzes
- Access to Global Peer Community
- Interview Prep Material
Buy for 65% OFF
₹20,000.00 ₹6,999.00

Mastering Mern Stack (WEB DEVELOPMENT)
- 65+ Live Classes & Recordings
- 24*7 Live Doubt Support
- 12+ Hands-on Live Projects & Deployments
- Comprehensive Notes & Quizzes
- Real-world Tools & Technologies
- Access to Global Peer Community
- Interview Prep Material
- Placement Assistance
Buy for 60% OFF
₹15,000.00 ₹5,999.00
Reach Out Now
If you have any queries, please fill out this form. We will surely reach out to you.
Contact Email
Reach us at the following email address.
Phone Number
You can reach us by phone as well.
+91-97737 28034
Our Location
Rohini, Sector-3, Delhi-110085