Stop 04 · Frontend with ReactTopics · 7/8

Custom Hooks

Part of the Full Stack Developer Roadmap

In short

When two components need the same logic, like fetching data or reading localStorage, don't copy-paste it. Pull it into a custom hook and reuse it like useState.

Your own reusable functions (prefixed `use...`) that extract and share stateful logic between components — commonly used to wrap API calls, forms, or auth logic cleanly.

The jaadu mascot sprinkles a spoonful of spice mix from one jar into three different pots.

Think of it like this

Ghar ka masala mix

Mummy grinds her garam masala once and uses it in many dishes. Each dish gets its own spoonful, so adding it to the dal doesn't change the sabzi. A custom hook is that mix: the logic is shared, but every component gets its own separate state.

Watch it happen

useLocalStorage at work

ThemeToggle
custom hook
localStorage

("theme", "light")

1/6ThemeToggle calls useLocalStorage("theme", "light"), just like it would call useState.

The big ideas

What you need to know

Starts with use

Name it useSomething. That tells React and the linter that the hook rules apply inside.

Built from other hooks

A custom hook is just a function that calls useState, useEffect or other hooks and returns what you need.

State is not shared

Two components using useToggle each get their own toggle. To share state, lift it up or use Context.

Cleaner components

The component reads like a sentence, const { data, error } = usePosts(), with the details tucked away.

See it in code

Walk through the code

ts
1import { useEffect, useState } from "react";2 3export function useLocalStorage<T>(key: string, initial: T) {4  const [value, setValue] = useState<T>(() => {5    const saved = localStorage.getItem(key);6    return saved !== null ? (JSON.parse(saved) as T) : initial;7  });8 9  useEffect(() => {10    localStorage.setItem(key, JSON.stringify(value));11  }, [key, value]);12 13  return [value, setValue] as const;14}15 16// const [theme, setTheme] = useLocalStorage("theme", "light");

1/3The lazy initial state reads localStorage once, falling back to initial.

It works like useState but survives a page reload. In Next.js, use it only in client code, since localStorage doesn't exist on the server.

Save yourself the pain

Common mistakes

Oops

Naming it getUserData and calling hooks inside.

Do this instead

Start the name with use, like useUserData. Otherwise the linter can't check the hook rules for you.

Oops

Expecting two components that call the same custom hook to share data.

Do this instead

Each call gets fresh state. Shared data needs Context, lifted state or a store like Zustand.

Your mission

Write three tiny hooks

~30 min

Quick check

Two components both call useCounter(). One of them clicks +1. What happens to the other?

Go deeper

  1. 1Extract a repeated data-fetching pattern into a `useFetch` or similar custom hook.
  2. 2Build a `useAuth` hook wrapping your auth context for easy access anywhere.
  3. 3Learn that custom hooks are just functions — they don't share state between usages.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge