Custom Hooks

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 2 min

Custom Hooks

Custom Hooks are one of the most powerful features of React. They allow you to extract stateful logic from your components into reusable JavaScript functions.

If two or more components share similar logic (like fetching data, subscribing to a window resize event, or managing form state), you don’t need to copy-paste the code. You can pull it out into a custom Hook.

Creating a Custom Hook

A custom Hook is simply a JavaScript function whose name starts with use (e.g., useWindowSize, useFetchUser).
Because its name starts with use, React (and the ESLint plugin) knows that the Rules of Hooks apply to it.

Here is an example of a component that tracks whether the user is online:

// Without a Custom Hook
function StatusBar() {
  const [isOnline, setIsOnline] = useState(true);
  
  useEffect(() => {
    function handleOnline() { setIsOnline(true); }
    function handleOffline() { setIsOnline(false); }
    
    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);
    return () => {
      window.removeEventListener('online', handleOnline);
      window.removeEventListener('offline', handleOffline);
    };
  }, []);

  return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>;
}

Now, imagine we also need a SaveButton that disables itself when the user is offline. Instead of duplicating the useState and useEffect logic, we extract it into a Custom Hook:

// 1. Define the Custom Hook
function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(true);
  
  useEffect(() => {
    function handleOnline() { setIsOnline(true); }
    function handleOffline() { setIsOnline(false); }
    
    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);
    return () => {
      window.removeEventListener('online', handleOnline);
      window.removeEventListener('offline', handleOffline);
    };
  }, []);
  
  // Return the piece of state we care about
  return isOnline; 
}

Using the Custom Hook

Now, both components can use the useOnlineStatus hook. The components become incredibly clean and declarative:

function StatusBar() {
  const isOnline = useOnlineStatus();
  return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>;
}

function SaveButton() {
  const isOnline = useOnlineStatus();

  function handleSaveClick() {
    console.log('Progress saved');
  }

  return (
    <button disabled={!isOnline} onClick={handleSaveClick}>
      {isOnline ? 'Save progress' : 'Reconnecting...'}
    </button>
  );
}

Custom Hooks Share Logic, Not State

It’s critical to understand that custom Hooks share stateful logic, not the state itself.

Every time you call a Hook inside a component, all the useState and useEffect calls inside of it are completely independent. If ComponentA and ComponentB both call useForm(), they get two completely separate form states.

If you need to share the actual state (data) between components, you need to lift the state up to a common parent or use Context.

Interview Questions

Q: What defines a “Custom Hook” in React?
A: A custom hook is simply a JavaScript function whose name starts with use (e.g., useFetch) and that calls other React Hooks (like useState or useEffect) inside of it.

Q: If two different components use the exact same custom hook, do they share the same state?
A: No. Custom hooks are a mechanism to reuse stateful logic, not state itself. Every time you call a custom hook, all the state and effects inside of it are completely isolated to the specific component calling it.