FrontendPrep
Menu
Topics
Questions
Guides
Challenges
Soon
Back to React Questions
reactEasy

React: How and When to Write Custom Hooks

Learn when to extract logic into custom React hooks, how hooks share state logic but not state instance, and guidelines for designing clean custom hook interfaces.

React: How and When to Write Custom Hooks

A fundamental React design pattern question is:

What are custom hooks? How do they help share logic between components, and do components using the same custom hook share the actual state values?

Custom hooks are one of the most powerful features of React's functional component model, allowing you to extract component logic into reusable functions. However, developers frequently confuse sharing state logic with sharing state instances.


1. What is a Custom Hook?

A custom hook is a Javascript function whose name starts with use and that can call other hooks (such as useState, useEffect, useContext, or useRef).

import { useState, useEffect } from 'react';
 
// A custom hook that tracks window size
export function useWindowWidth() {
  const [width, setWidth] = useState(0);
 
  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', handleResize);
    handleResize(); // call initially
 
    return () => window.removeEventListener('resize', handleResize);
  }, []);
 
  return width;
}

2. Share Logic, Not State Instance

The most important rule of custom hooks is: Custom hooks share stateful logic, not state itself.

Each call to a custom hook creates an entirely isolated state instance. If two different components call useWindowWidth(), they will both set up their own independent event listeners and state objects:

Component A                      Component B
┌──────────────────┐             ┌──────────────────┐
│ useWindowWidth() │             │ useWindowWidth() │
│  ├─ useState(0)  │ ◄─Independent─►  ├─ useState(0)  │
│  └─ useEffect()  │             │  └─ useEffect()  │
└──────────────────┘             └──────────────────┘

If you need two components to share the actual state values rather than just the logic, you must:

  1. Lift the state up to their closest common parent component and pass it down as props.
  2. Use React Context to broadcast the state value down the component tree.
  3. Use a global state management library (like Zustand or Redux).

3. When to Write a Custom Hook

You should extract logic into a custom hook when:

  • Complex Effect Cleanup: You are handling web APIs (like IntersectionObserver, WebSocket connections, event listeners, or timers) that require standard setup and teardown.
  • Form Handling & Validation: You want to reuse form validation or input binding logic across different form components.
  • Data Fetching / Queries: Standardizing API fetches, error states, and loading states (e.g. creating useFetch).
  • Reducing Component Size: A component body contains 50+ lines of raw hooks (state/effects) making the rendering UI code difficult to read. Extracting those hooks into a descriptive custom hook (e.g. useUserProfile) improves readability.

Senior-Level Interview Answer

Custom hooks are user-defined JavaScript functions prefixed with "use" that compose built-in React hooks to encapsulate stateful logic. The critical runtime characteristic of custom hooks is that they do not share state instances between components; every invocation of a custom hook instantiates a unique, isolated set of state variables and effects in React's internal fiber tree. If shared data is required, state must be lifted to a common ancestor, placed in a Context Provider, or managed via external state stores. Custom hooks should be created to extract complex side effects (such as event listeners or polling loops), abstract reusable form or API workflows, and clean up UI components by segregating presentation layers from business logic.


Common Interview Mistakes

❌ Thinking custom hooks share global state values

Assuming that updating state inside a custom hook in Component A will automatically trigger a state update in Component B which also uses the hook. Each invocation is completely isolated.

❌ Omitting the use prefix

React relies on the use prefix convention to enforce the Rules of Hooks (like calling hooks only at the top level). If you name your hook getWindowWidth instead of useWindowWidth, React's linter cannot verify that it safely uses hooks internally.


Key Takeaways

  • Prefixed Convention: Custom hooks must start with the prefix use so React's linter can validate the hooks call rules.
  • State Isolation: Every component calling a custom hook sets up its own isolated state and effects; they do not share data values.
  • Logic Reusability: Custom hooks extract repetitive code blocks like API queries, form inputs, or event listeners into singular modules.
  • UI Decoupling: They separate structural business logic and side effects from rendering markup, improving code readability.
  • State Sharing: To share actual state instances, you must lift the state up, use React Context, or implement a state management tool.

Share this Resource

Help other developers level up by sharing this study guide.

More Technical Questions

Expand your mastery. Deep dive into other frontend interview challenges in this category.