React Interview Questions

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.

By TechCoder TeamLast updated: 2026-06-15
In a Nutshell

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:

  1. Only call Hooks at the top level (not inside loops, conditions, or nested functions)
  2. 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:

  1. Accessing DOM elements
  2. 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 paint
  • useLayoutEffect: 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

useStateuseReducer
Simple state logicComplex state logic
Individual state valuesState transitions via reducer function
Easier for beginnersGreat for predictable state changes
Good for basic componentsGood for Redux-like patterns without Redux

When to use which:

  • Use useState for simple state (e.g., boolean, string, number)
  • Use useReducer when state depends on previous state, or when you have complex logic

Question 46: useEffect Cleanup Function

Cleanup function runs when:

  1. The component unmounts
  2. 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

  1. Use React.memo for components
  2. Use useCallback for callbacks
  3. Use useMemo for computations
  4. Use state sparingly
  5. 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

  1. Forgetting the dependency array (runs every render)
  2. Not cleaning up effects (causes memory leaks)
  3. Putting props/state in the dependency array that don't affect the effect
  4. 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.