June 25 2025
When to Create a Custom Hook and When to Stop
A good custom hook encapsulates recurring behavior. A bad hook only moves the mess to another file.
Andrews Ribeiro
Founder & Engineer
4 min Intermediate Frontend
The problem
One of the most abused abstractions in frontend work is the custom hook.
The reasoning usually goes like this:
- the component grew
- it looks ugly
- let’s “move it into a hook”
But that does not solve the problem by itself.
A lot of the time the result is:
- a smaller component
- equally confusing logic
- hidden dependencies
- a nice name on top of badly defined responsibility
In other words:
the file got shorter, but the system did not get clearer.
Mental model
A custom hook does not exist to reduce scroll.
It exists to encapsulate a behavior that:
- repeats
- has an identifiable boundary
- becomes clearer when exposed as an API
Short version:
extract a hook when the abstraction improves understanding for the caller, not only when it improves aesthetics for the author.
When it is usually worth creating a hook
1. When there is repeatable behavior
Examples:
- syncing query string with filters
- handling remote pagination
- encapsulating subscribe/unsubscribe
- coordinating loading, error, and retry for a recurring flow
If this appears across several screens with the same intent, it makes sense to name it.
2. When there is noisy integration worth isolating
Sometimes the problem is not literal repetition.
It is that there is a verbose or noisy integration:
- observer
- listener
- media query
- analytics
- polling
In those cases, the hook can hide incidental detail and let the screen speak more in terms of product behavior.
3. When the usage API is better than the original implementation
Compare:
- a component full of
useEffect,useRef, cleanup, and synchronization - a
useSearchResults({ query, page })
If the abstraction name helps explain the intent, the extraction may be good.
When it usually is not worth it
1. When the code is still too specific to that screen
If the hook needs to know:
- a specific layout
- tracking ids from that page
- navigation rules from that flow
- local visual details
then it probably is not a reusable hook yet.
It is only screen logic trying to leave too early.
2. When you are hiding coupling
Some hooks look elegant until you open the file and find:
- fetch
- analytics
- navigation
- feature flags
- data transformation
- permission logic
all together.
That is not encapsulation.
It is packaged coupling.
3. When the abstraction was born only to “clean JSX”
If the main motivation was:
- “the component is large”
- “it looks ugly”
- “the PR looks better this way”
it is worth pausing.
Maybe the problem is responsibility boundary, not missing hooks.
Simple example
Imagine a user search screen.
Bad version:
- the page reads query params
- debounces input
- triggers fetch
- handles loading
- cancels the previous request
- logs analytics
All inside the component.
Now imagine that same pattern appears on other screens.
Then a hook like useSearchResults may make sense if it:
- takes clear inputs
- returns clear state
- encapsulates the search cycle
- does not couple itself to visual details
But if it returns fifteen things and depends on half the page context, maybe it was not ready to exist yet.
Common mistakes
- Extracting a hook before understanding the stable behavior.
- Creating a one-use hook and calling it reuse.
- Putting into the hook everything that was hard to name in the component.
- Making the hook hide a dangerous side effect with no explicit contract.
How a senior thinks
People with more judgment usually ask:
- is this an abstraction or a hiding place?
- could another screen really use this?
- did the API become clearer than the original implementation?
- am I removing coupling or only moving it somewhere else?
That last question avoids a lot of fake abstraction.
Interview angle
This topic shows up a lot in:
- code review
- pair programming
- frontend architecture questions
The interviewer rarely wants to hear “I would extract this into a hook” as an automatic answer.
They want to see whether you know:
- why to extract
- what the hook should encapsulate
- what should still stay in the screen
A strong answer usually follows this pattern:
- first name the behavior
- then define the responsibility
- only then propose the hook
Closing thought
A good custom hook gives a name, a boundary, and an interface to something that already deserved to exist.
A bad custom hook is just a tired component trying to look architected.
If the abstraction does not improve understanding for the caller, it still has not paid the rent.
Quick summary
What to keep in your head
- A custom hook is not there to hide volume. It is there to encapsulate behavior that deserves a better interface.
- If the abstraction still depends on too many screen details, it may not deserve to become a hook yet.
- A good hook reduces incidental coupling. A bad hook only spreads dependencies into another file.
- In frontend work, good extraction usually starts when you recognize a stable behavior, not when you get tired of the component size.
Practice checklist
Use this when you answer
- Does this hook encapsulate repeatable behavior, or did it only remove lines from the component?
- Does someone using this hook understand its API and side effects quickly?
- Did the extraction reduce context dependency, or did it only move the mess to another file?
- If this code is still changing every week, does it make sense to abstract it now?
You finished this article
Share this page
Copy the link manually from the field below.