When to Create Custom React Hooks
React hooks are just functions that let components share stateful behavior. A custom hook packages that behavior so you can reuse it without copy-pasting the same effect, subscription, or state logic everywhere.
A Small Example
Here is a simple counter with a threshold alert:
function Counter() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
if (count === 10) {
window.alert('you have counted to 10! great job!');
} else if (count >= 100) {
window.alert('ok maybe you should get on with your day now');
}
}, [count]);
return <button onClick={() => setCount((value) => value + 1)}>{count}</button>;
}
That works, but the component is now doing two jobs:
- rendering a button
- managing counter behavior
A custom hook lets you separate those concerns:
function useCounter() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
if (count === 10) {
window.alert('you have counted to 10! great job!');
} else if (count >= 100) {
window.alert('ok maybe you should get on with your day now');
}
}, [count]);
return {
count,
increment: () => setCount((value) => value + 1),
};
}
function Counter() {
const {count, increment} = useCounter();
return <button onClick={increment}>{count}</button>;
}
When A Custom Hook Is A Good Fit
Use a custom hook when the logic:
- uses React state or lifecycle hooks
- is needed in more than one component
- is hard to read when left inline inside a component
- represents a coherent behavior, not just a utility helper
A few examples that usually justify a hook:
- syncing state with local storage
- subscribing to a websocket or event source
- managing modal open/close behavior
- coordinating a form with validation and submission state
When Not To Make One
A common mistake is turning every helper into a hook.
If the function does not use React state or effects, it probably should not start with use.
If a function does not rely on React state, effects, or context, it is usually just a JavaScript function. Do not call it a hook unless it actually behaves like one.
That distinction matters because hook naming implies React rules, React lifecycle, and React mental overhead.
A plain helper like formatCurrency() should stay a plain function.
A stateful behavior like useSession() or useToastQueue() is a better candidate for a hook.
Too Many Hooks Can Hurt
Custom hooks are powerful, but they can also add layers of indirection. If every component pulls in five hooks, it becomes harder to tell where state lives and how updates happen.
A good test is whether the hook makes the calling component easier to read. If the answer is no, the extraction may have been premature.
Before extracting a hook, ask:
- Will this logic be reused?
- Does the extraction remove meaningful complexity from the component?
- Does the hook name communicate what the behavior does?
- Would I still understand the flow if I had to debug it later?
A Practical Rule Of Thumb
If the code is simple and only used once, keep it inline. If the logic is stateful, reusable, or noisy enough to distract from rendering, extract a hook. If the logic is not stateful at all, use a normal function.
That gives you three clean buckets:
- component code for rendering
- custom hooks for reusable React behavior
- ordinary functions for everything else
Summary
- Use a custom hook to package reusable React behavior built on state, effects, or context.
- Do not make a hook just because a helper looks reusable.
- Keep simple logic inline when that is the clearest option.
- Use plain functions for non-React logic.