As someone who's written React for several years now, it took me far too long to discover the joy of custom hooks - in fact it took me over 3 years! In this post, I'm going to show you how to take advantage of one of React's most powerful features.
What even is a hook?
A hook is quite simply a function which lets you hook into React's rendering lifecycle. Let's briefly look at the most common hook useState
:
const [state, setState] = useState(0)
As you can see, useState
hooks into React and provides an interface for managing state - it's entirely abstracted away the complexity that would otherwise be associated with it.
When we think of hooks as reusable abstractions, it makes them easier to reason about. As a component is reusable markup, a hook is just reusable logic!
I like to refer to React's built-in hooks as atomic - in that we typically use and combine them to build our own custom ones.
Our first custom hook
Let's build a basic custom hook to manage the state of a toggleable component (modal, dropdown, etc):
useToggle.ts
import { useState } from "react";
function useToggle(initial = false) {
const [state, setState] = useState(initial);
return [
state,
{
open: () => setState(true),
close: () => setState(false),
toggle: () => setState((state) => !state)
}
] as const;
}
export default useToggle;
Quick tip: using
as const
on our return value tells TypeScript to infer the type as a readonly tuple instead of a union type array! 😁
In this example, all we've done is wrap the use state hook with some logic that would otherwise pollute a component - look how easy it is to implement:
App.tsx
function App() {
const [state, { open, close, toggle }] = useToggle();
return (
<div className="App">
<button onClick={open}>Open</button>
<button onClick={close}>Close</button>
<button onClick={toggle}>Toggle</button>
{state && <div>Hello!</div>}
</div>
);
}
...and that's it! I hope that after seeing this you can start to see how you might implement other hooks - try useQueue
and useStack
.
In a future post I'll detail how to implement some more complicated behaviour, and some common design patterns for handling refs, external data and more.
Top comments (0)