Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Effects, Refs and Reuse  ›  Capstone Project

Custom Hooks — Reusing Logic

Creating Custom Hooks 17 minA custom hook is a function whose name starts with use and that calls other hooks, letting components share stateful logic while each keeps its own separate state.

Custom Hooks — Reusing Logic

BookCard has an open/closed state with open, close and toggle helpers. So does AuthorCard. So does the filters panel. The same five lines, pasted three times. Components let you reuse markup; custom hooks let you reuse the logic behind it.

The rule

A function named use-something that calls hooks: shared logic, separate state.

// useToggle.js
import { useState } from 'react';

export function useToggle(initial = false) {
  const [isOpen, setIsOpen] = useState(initial);
  const open = () => setIsOpen(true);
  const close = () => setIsOpen(false);
  const toggle = () => setIsOpen(o => !o);
  return { isOpen, open, close, toggle };
}
function BookCard({ book }) {
  const { isOpen, toggle } = useToggle();
  return (
    <article>
      <h2 onClick={toggle}>{book.title}</h2>
      {isOpen && <p>{book.summary}</p>}
    </article>
  );
}

Named use-something. The use prefix is a promise: "this function calls hooks, so the rules of hooks apply to it." The linter relies on the name to check it, and readers rely on it too. A helper that calls no hooks should not start with use.

Calls hooks. Inside, you can use any hook — useState, useEffect, useRef, even other custom hooks. It returns whatever is useful: a value, an object, an array.

Shared logic, separate state. This surprises many people. Each component that calls useToggle() gets its own isOpen. Opening one book card does not open the others. A custom hook shares how the state works, not the state itself. To truly share one value, lift it up or use context.

Older patterns. Before hooks, logic was shared in two other ways you will still meet in older code:

  • A higher-order component is a function that takes a component and returns a new, wrapped one: export default withToggle(BookCard).
  • A render prop is a prop holding a function that returns JSX: <Toggle render={isOpen => ...} />.

Both still work, but they add wrapper components and nesting. A custom hook is just a function call at the top of a component, which is why modern code prefers it.

The shortcut

Spot the repeat, cut the hook lines out, and name what they do. Whatever the components need back becomes the return value.

Extracting useToggleStep 1 of 4
  1. Spot the repeat

    BookCard and AuthorCard both have useState(false) plus three helper functions.

Drills

Answer fast — trust the rule.

quick drill

Which name is right for a function that calls useState and useEffect to track window width?

quick drill

Two components each call useToggle(). One calls toggle(). What happens to the other?

quick drill

What is withToggle(BookCard) an example of?

quick drill

Where can a custom hook be called?

Remember

  • A function named use-something that calls hooks: shared logic, separate state.
  • Spot the repeat, cut the hook lines out, return what callers need.
  • Trap: expecting two calls to share state; use lifting or context for that.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainExtracting a hook

Both BookCard and AuthorCard keep an isOpen state with open, close and toggle functions, written twice. Explain how you would extract a custom hook for this, how each component uses it, whether the two cards now share one isOpen, and how this compares with older patterns such as higher-order components or render props.