DEV Community

Cover image for An introduction to custom React hooks
Tom Mitchelmore
Tom Mitchelmore

Posted on • Updated on

An introduction to custom React hooks

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)
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

...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)