Skip to main content

Custom Hooks

Custom Hooks

In React you can create your own Hooks for your application’s needs. Custom hooks are regular JavaScript functions prefixed with the word "use" and they can call other hooks if needed.

In the below example code to determine the status of network connection is moved into the custom hook useOnlineStatus and is resued in different components.

function useOnlineStatus() {
const [isOnline, setIsOnline] = useState(true);

useEffect(() => {
function handleOnline() {
setIsOnline(true);
}
function handleOffline() {
setIsOnline(false);
}
window.addEventListener("online", handleOnline);
window.addEventListener("offline", handleOffline);
return () => {
window.removeEventListener("online", handleOnline);
window.removeEventListener("offline", handleOffline);
};
}, []);

return isOnline;
}

function StatusBar() {
const isOnline = useOnlineStatus();

return <h1>{isOnline ? "✅ Online" : "❌ Disconnected"}</h1>;
}

function SaveButton() {
const isOnline = useOnlineStatus();

function handleSaveClick() {
console.log("✅ Progress saved");
}

return (
<button disabled={!isOnline} onClick={handleSaveClick}>
{isOnline ? "Save progress" : "Reconnecting..."}
</button>
);
}

Hook names always start with use

  • Hook names must start with use followed by a capital letter, like useState (built-in) or useOnlineStatus (custom, like earlier on the page). Hooks may return arbitrary values.

  • This convention ensures clarity in components by signaling where state, effects, and other React features are located. For instance, a function named getColor() suggests the absence of React state, while useOnlineStatus() likely includes calls to other Hooks.

Custom Hooks let you share stateful logic, not state itself

Custom hooks allow you to encapsulate and reuse logic related to state management, effects, or other React features without sharing the actual state. The state remains internal to the custom hook, and only the logic is shared among components.

In the below example CounterComponent and AnotherComponent both use the same custom hook but have separate instances of state.

// Custom hook with stateful logic
function useCounter(initialValue) {
const [count, setCount] = useState(initialValue);

const increment = () => {
setCount(count + 1);
};

const decrement = () => {
setCount(count - 1);
};

return [count, increment, decrement];
}

// Component using the custom hook
function CounterComponent() {
// Using the custom hook to get stateful logic
const [count, increment, decrement] = useCounter(0);

return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}

// Another Component using the same custom hook
function AnotherComponent() {
// Using the same custom hook to get separate stateful logic
const [count, increment, decrement] = useCounter(100);

return (
<div>
<p>Count in Another Component: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}

export default function App() {
return (
<div>
<CounterComponent />
<AnotherComponent />
</div>
);
}

When to use Custom Hooks

You shouldn’t need Effects very often, so if you’re writing one, it means that you need to “step outside React” to synchronize with some external system or to do something that React doesn’t have a built-in API for. Consider wrapping your Effect in a custom hook for clarity.

Here are some scenarios in which you might consider using custom hooks:

  1. Reuse of Logic: Use custom hooks when you find yourself duplicating logic across multiple components.
  2. Sharing Logic Across Components: Use custom hooks when you want to share logic among components that may not share a direct parent-child relationship. Custom hooks enable you to share logic between components at different levels of your component tree.
  3. Handling Side Effects: When dealing with side effects (e.g., data fetching, subscriptions), custom hooks can encapsulate the logic related to these effects. This separation makes it easier to manage side effects in a modular and organized way.