Building Custom React HooksEntry 4 of 5

Each Call Gets Its Own State

Every component that calls a custom hook gets a separate, independent copy of the hook's state and effects.

Notes

  • Custom hooks share logic, not data. Calling useFetch in two components runs two requests and keeps two separate sets of isFetching, error, and fetchedData.
  • Think of a custom hook as a factory: each call creates new state, just like calling useState twice.
  • To share the same state between components, combine the hook with Context (see Context API & useReducer, Entry 4) or use a store such as Redux Toolkit.

What / Why / When

What

Per-component state isolation.

Why

Components stay independent and predictable; one component's data can't change another's.

When to share instead

Several components must see the same data at the same time (a cart, the logged-in user).

Code compare

React
function PlayersSummary() {  const { fetchedData } = useFetch(fetchPlayers, []); // request #1, own state  return <p>{fetchedData.length} players</p>;}​function PlayersTable() {  const { fetchedData } = useFetch(fetchPlayers, []); // request #2, separate state  return <table>{/* ... */}</table>;}

Where state lives depends on the tool, which maps neatly onto React's options:

Angular
// Per component (like a custom hook): each call creates new signalsprotected players = injectFetch(() => firstValueFrom(this.playersService.fetchPlayers()), []);​// Shared app-wide (like Context or a global store): one instance for everyone@Injectable({ providedIn: 'root' })export class PlayersStore {}​// Shared within a subtree (like a Context provider around one section)@Component({ selector: 'app-team', providers: [PlayersStore], template: `...` })export class TeamComponent {}

Differences and gotchas

  • A common mistake coming from Angular: assuming a custom hook behaves like a providedIn: 'root' service. It doesn't; it behaves like a function called per component.

Quick reference

ScopeReactAngular
Per componentCustom hookFunction with signals / component-level providers
Shared in a subtreeContext provider around the subtreeService in a component's providers
Shared app-wideContext at the root / Redux ToolkitprovidedIn: 'root' service