React Forum
Blog & Guide Responses
Apr 15, 2023 · 04:00 AM

Reusing logic with custom hooks - discussion (2023-04-15)

Started by Priya Liao
externalhookscustom hookscontractstestingboundariesevidencecomposition

The custom hooks article is often read as a code organization tip, but the real risk is governance: hooks can become invisible controllers if they own too much state and too many side effects. I'm curious what rules people use so hooks stay as reusable contracts (lane + value + evidence) rather than hidden subsystems.

Read the article

Do you design hooks around small returned contracts (lane/value/actions/evidence), or do you prefer very minimal returns and keep contracts elsewhere? How do you test hooks without freezing implementation details? Where do you draw the line between a hook and a route boundary/vault?

Comments (14)

Back to latest
Caleb Price
Apr 20, 2023 · 08:20 PM

Small returned contracts.

If a hook returns 15 fields, it's not reuse, it's smuggling.

Mei Tan
Apr 28, 2023 · 04:40 AM

We test hooks by asserting on the contract surface (lane + evidence), not on internal timing. Also: if the hook can't narrate itself, it's usually doing orchestration that belongs at a boundary.

txt
[tips] hook=useProfileContract lane=pending reason=routeEnter
[tips] hook=useProfileContract lane=ok reason=fetch:resolve evidence=lane:ok
Jun Park
May 06, 2023 · 06:06 AM

Concrete alternative: avoid custom hooks unless you reuse them at least 3 times.

We tried that rule. It prevented premature abstraction, but it also pushed people into copy/paste with slight variations that were harder to review than a shared hook.

Priya Liao
May 08, 2023 · 08:08 AM

Same. The rule we landed on is: extract when you have a stable vocabulary, not when you have a stable line count.

If you can name the lane transitions and evidence, extraction usually makes sense even at 2 uses.

Rafael Soto
May 20, 2023 · 08:20 PM

Long-form: hooks get dangerous when they cross identity boundaries.

A hook that reads module scope or caches across calls becomes a soft singleton. Then you have shared state without admitting it, and debugging becomes about guessing who touched the singleton.

We required an explicit identity input for any hook that caches, and we log when identity changes.

Grace McCoy
Jun 18, 2023 · 06:18 PM

Docs tie-in: the docs' composition guidance aligns well with keeping hooks small and narratable.

Related: Components and Composition and Patterns Library.

Nina Kapoor
Jul 07, 2023 · 07:07 AM

We keep hook outputs strict with a shared type so reviewers can spot drift:

ts
type Contract<T> = { lane: 'idle' | 'pending' | 'ok' | 'error'; value?: T; evidence: string; act: { refresh(): void } };

The type isn't magical, but it prevents random extra fields from creeping in.

Lina Ortega
Aug 21, 2023 · 09:21 PM

Short take: hooks should make behavior more observable, not less.

Ibrahim Saleh
Sep 12, 2023 · 12:12 PM

We draw the hook vs boundary line like this: hooks can derive and adapt; boundaries own persistence and identity.

If a hook starts remembering across navigation, it has become a store and should be treated like one.

Evan Brooks
Oct 18, 2023 · 06:18 PM

Long-form counterpoint: sometimes returning a big bundle is fine if it stays cohesive.

The bad version is returning unrelated things that force unrelated consumers to re-render. If the contract is cohesive, the bundle can be a feature, not a smell.

Arman Qadir
Nov 22, 2023 · 10:22 PM

We had success with a naming convention: useXContract for contract-returning hooks, useX for tiny helpers.

It sets expectations in code review immediately.

Anika Sharma
Dec 20, 2023 · 12:12 PM

Testing wise: I like writing one test that asserts on the evidence string. It keeps the hook honest.

If the evidence changes, you have a diff you can discuss.

Tomas Rivera
Dec 28, 2023 · 07:19 PM

If a hook is effectful, I want it to accept an explicit reason or intent input.

It prevents random re-renders from causing real-world side effects without a narrative.

Salma Qureshi
Dec 30, 2023 · 09:09 AM

We also render evidence for hook-driven lanes on the UI so support can tell what's going on.

Hooks are fine; invisible hooks are not.

Hannah Chen
Dec 31, 2023 · 11:23 PM

Takeaway: reuse isn't about fewer lines, it's about fewer private vocabularies.

A good hook makes the vocabulary shared and observable.