Building Custom React HooksEntry 1 of 5

What a Custom Hook Is

A custom hook is a function whose name starts with use and that calls other hooks (useState, useEffect, etc.) to package reusable logic.

Notes

  • A custom hook wraps logic that would otherwise be copied between components: data fetching, subscriptions, timers, form handling.
  • The use prefix is required. It tells React and the eslint-plugin-react-hooks linter to apply the Rules of Hooks to the function (see React Essentials, Entry 6).
  • Custom hooks follow the same rules as built-in hooks: call them only inside components or other hooks, and only at the top level.
  • A custom hook shares logic, not state. Each component that calls it gets its own state (Entry 4).
  • It can return anything: a value, an object, a tuple, or functions.

What / Why / When

What

A reusable function built from other hooks.

Why

Removes duplicated stateful logic and keeps components focused on rendering.

When

The same combination of state and effects appears in more than one component.

Use case

A useFetch hook that handles loading, error, and data state for any request.

Code compare

React
import { useState } from "react";​// ✅ A custom hook: starts with "use" and calls other hooksexport function useToggle(initialValue = false) {  const [isOn, setIsOn] = useState(initialValue);​  function toggle() {    setIsOn((prev) => !prev);  }​  return [isOn, toggle] as const;}​// Usagefunction Menu() {  const [isOpen, toggleOpen] = useToggle();  return <button onClick={toggleOpen}>{isOpen ? "Close" : "Open"} menu</button>;}

Angular has no hooks, so reusable logic takes one of two forms:

  • A service when the logic or state should be shared (see Context API & useReducer, Entry 4).
  • A plain function that creates signals and, when needed, calls inject(). Functions that call inject() must run in an injection context (a field initializer or constructor), and by convention are often named injectX.
Angular
import { signal } from "@angular/core";​export function createToggle(initialValue = false) {  const isOn = signal(initialValue);​  return {    isOn: isOn.asReadonly(),    toggle: () => isOn.update((prev) => !prev),  };}
Angular
@Component({  selector: "app-menu",  template: ` <button (click)="menu.toggle()">{{ menu.isOn() ? "Close" : "Open" }} menu</button> `,})export class MenuComponent {  protected menu = createToggle();}

Differences and gotchas

  • React requires the use prefix and the Rules of Hooks. Angular functions have no naming rule; only functions that call inject() or effect() must run in an injection context.
  • Angular also reuses DOM behavior through directives (including hostDirectives), which have no direct React equivalent.

Quick reference

ReactAngular
function useX() { useState(...) }Function creating signals / service
use prefix requiredNo naming rule (injectX by convention)
Rules of HooksInjection context for inject()/effect()