JS Guide
HomeQuestionsTopicsCompaniesResources
BookmarksSearch

Built for developers preparing for JavaScript, React & TypeScript interviews.

ResourcesQuestionsSupport
HomeQuestionsSearchProgress
HomeTopicsreactHooks
PrevNext
react
intermediate
20 min read

Hooks

custom-hooks
hooks
side-effects
state
useCallback
useEffect
useMemo
useRef
useState

Hooks let functional components manage state (useState), run side effects (useEffect), access refs (useRef), and extract reusable logic into custom hooks — all following strict rules about call order.

Key Points

1Rules of Hooks

Only call at top level (no loops/conditions) and only in React functions. React depends on consistent call order to match hooks to their state.

2useEffect Lifecycle

Runs after render. Dependency array controls re-runs: no array = every render, [] = mount only, [deps] = when deps change. Return cleanup function.

3useRef for Persistence

Mutable .current container that persists across renders without triggering re-renders. Used for DOM access and instance variables.

4Custom Hooks

Extract reusable stateful logic into use-prefixed functions — the modern replacement for HOCs and render props.

5useMemo and useCallback

Cache values and function references between renders — optimization tools for memoized components, not defaults for every computation.

What You'll Learn

  • Explain useState, useEffect, and useRef and their common patterns
  • Know the Rules of Hooks and why they exist
  • Create custom hooks to extract and share reusable stateful logic

Deep Dive

Hooks (introduced in React 16.8) are functions that let you use React features in functional components. They replace class component patterns with a simpler, more composable API.

Rules of Hooks

Two rules must be followed for hooks to work correctly:

  1. Only call hooks at the top level — never inside loops, conditions, or nested functions. React relies on the order hooks are called to associate each hook with its state. Conditional calls break this ordering.
  2. Only call hooks from React function components or custom hooks — never from regular JavaScript functions or class components.

The eslint-plugin-react-hooks enforces these rules automatically.

useState

const [value, setValue] = useState(initialValue) declares a state variable. The setter triggers a re-render. For expensive initial values, pass a function: useState(() => computeExpensiveValue()) — the function runs only on the first render. The setter accepts a direct value or an updater function: setValue(prev => prev + 1). Use the updater form when the new state depends on the previous state to avoid stale closure bugs.

useEffect

useEffect(setup, dependencies?) runs side effects after the component renders. The setup function connects to external systems (APIs, subscriptions, DOM manipulation). The optional dependency array controls when the effect re-runs:

  • No array: runs after every render
  • Empty array []: runs once after mount
  • With dependencies [a, b]: runs when a or b change

Return a cleanup function to disconnect: useEffect(() => { const sub = subscribe(); return () => sub.unsubscribe(); }, []). Cleanup runs before the effect re-runs and when the component unmounts.

Common patterns: fetching data on mount, subscribing to events, setting up timers, updating document title.

useRef

const ref = useRef(initialValue) creates a mutable container with a .current property that persists across renders without triggering re-renders when changed. Two primary uses:

  1. DOM access: pass ref to a JSX element's ref attribute to get the DOM node. ref.current is the actual DOM element after render.
  2. Instance variables: store values that need to persist across renders but shouldn't trigger re-renders (timer IDs, previous values, flags).

Key difference from state: updating ref.current does not cause a re-render. Don't read or write refs during rendering — only in event handlers and effects.

useMemo and useCallback

useMemo(() => expensiveComputation(a, b), [a, b]) caches a computed value, recomputing only when dependencies change. useCallback(fn, [deps]) caches a function reference — equivalent to useMemo(() => fn, [deps]). Use these for optimization when passing values/callbacks to memoized child components (React.memo), not as a default for every value.

Custom Hooks

Custom hooks extract reusable stateful logic into functions prefixed with use. They can call any other hooks and return any values.

JavaScript
function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    const stored = localStorage.getItem(key);
    return stored ? JSON.parse(stored) : initialValue;
  });
  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);
  return [value, setValue];
}

Common patterns: useFetch (data fetching), useDebounce (debounced values), useMediaQuery (responsive breakpoints), useLocalStorage (persistent state), useOnClickOutside (click-away detection).

Key Interview Distinction

Hooks must be called in the same order every render (no conditional calls). useState manages state, useEffect handles side effects with cleanup, useRef provides mutable containers without re-renders. Custom hooks are the modern replacement for HOCs and render props for logic reuse. useMemo/useCallback are performance optimizations, not defaults.

Fun Fact

The Rules of Hooks exist because React stores hook state in an ordered array internally. When a component renders, React walks through the array in order, matching each useState/useEffect call to its stored value. If you put a hook inside a condition, the array positions shift and hooks get the wrong state — which is why the order must be identical on every render.

Learn These First

State

beginner

Components

beginner

Continue Learning

State

beginner

Performance Optimization

advanced

Advanced Patterns

advanced

Practice What You Learned

Explain the useState and useEffect hooks and their common patterns.
mid
hooks
useState manages local state in functional components, returning a value and setter function. useEffect handles side effects (data fetching, subscriptions, DOM manipulation) and runs after render. The dependency array controls when effects re-run.
What are custom hooks and how do you create them?
mid
hooks
Custom hooks are JavaScript functions starting with 'use' that encapsulate reusable stateful logic. They can use other hooks and share logic between components without duplicating code or adding components to the tree.
What is useRef and when should you use it?
mid
hooks
useRef creates a mutable reference that persists across renders without causing re-renders when changed. Use it for accessing DOM elements, storing mutable values that don't need to trigger updates, and keeping references to timers or previous values.
How would you implement a useLocalStorage custom hook?
mid
custom-hooks
A useLocalStorage hook syncs React state with the browser's localStorage, providing a useState-like API that automatically persists values across page reloads. It handles JSON serialization, error recovery, SSR safety, and can synchronize across browser tabs via the storage event.
How would you implement a useFetch custom hook?
mid
custom-hooks
A useFetch hook encapsulates data fetching logic with loading, error, and data states. It uses AbortController to handle cleanup and race conditions when the URL changes or the component unmounts, and can support refetch and basic caching.
How do React component lifecycle methods map to hooks in functional components?
mid
lifecycle
useEffect with an empty dependency array replaces componentDidMount, useEffect with dependencies replaces componentDidUpdate, and the useEffect cleanup function replaces componentWillUnmount. However, hooks represent a different mental model focused on synchronizing with external systems rather than responding to lifecycle events.
Build an autocomplete/typeahead search component in React that fetches suggestions from an API with debouncing, keyboard navigation, and highlighted matching text.
mid
machine-coding
An autocomplete component debounces user input, fetches matching suggestions from an API, renders a dropdown with keyboard navigation (arrow keys + Enter), highlights the matched portion of each suggestion, and handles edge cases like race conditions and empty states.
Implement a basic version of useState from scratch.
senior
hooks
A simplified useState uses a module-level array to store state values and an index counter to track which state slot to use. The setter updates the stored value and triggers a re-render. The call-order dependency on the array index explains why hooks cannot be called conditionally.
Implement a basic version of useEffect from scratch.
senior
hooks
A simplified useEffect stores effect callbacks and their dependency arrays in a module-level array. After each render, it compares current dependencies against previous ones using shallow equality and runs the effect callback (plus its cleanup) only when dependencies have changed.
Previous
React Fundamentals
Next
React Internals
PrevNext