R
Rishtaara
React: The Complete Guide
Lesson 23 of 28Article16 min

Custom Hooks

A custom hook is a function that calls other hooks. Name it useSomething. It lets you share stateful logic between components without copy-paste.

Custom Hooks — extract reusable logic

A custom hook is a function that calls other hooks. Name it useSomething. It lets you share stateful logic between components without copy-paste.

Real-life example: Custom hooks are family recipes — write once, any kitchen (component) can follow the same steps.

useFetch custom hook
import { useState, useEffect } from "react";

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    let cancelled = false;
    setLoading(true);
    fetch(url)
      .then((r) => r.json())
      .then((d) => { if (!cancelled) setData(d); })
      .catch((e) => { if (!cancelled) setError(e.message); })
      .finally(() => { if (!cancelled) setLoading(false); });
    return () => { cancelled = true; };
  }, [url]);

  return { data, loading, error };
}

function Courses() {
  const { data, loading, error } = useFetch("/api/courses");
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error}</p>;
  return <ul>{data.map((c) => <li key={c.id}>{c.title}</li>)}</ul>;
}

More custom hook ideas

useLocalStorage, useDebounce, useWindowSize, useAuth — all follow the same pattern: hooks inside, return values and functions.

Real-life example: useLocalStorage is a pocket notebook that syncs with a locker (browser storage) — open any component, same notes appear.

Custom hooks return data and functions — not JSX. Keep UI in components.
useLocalStorage sketch
function useLocalStorage(key, initial) {
  const [value, setValue] = useState(() => {
    const saved = localStorage.getItem(key);
    return saved ? JSON.parse(saved) : initial;
  });

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
}