React: How to create a Custom Hook

Robin Wieruch

React introduced Hooks quite a while ago. With their release, Hooks gave function components the ability to use state and side-effects with built-in Hooks such as React’s useState Hook and React’s useEffect Hook.

There are only a handful built-in Hooks (e.g. useReducer, useCallback, useMemo, useContext) provided by React though. However, by using these Hooks as a foundation, React developers can create their own hooks called custom hooks. In this tutorial, I will walk you through creating a custom hook as a learning experience.

Before we create a custom hook, you need to know that there are two rules to creating one:

  • Custom Hooks are named with “use” as prefix. For example, a custom hook could be named useLocalStorage or useAuthentication. In our case, the custom hook will be named useBoolean.
  • Custom Hooks consist of built-in React Hooks or other custom Hooks. Therefore a custom Hook is always a new composition of one or multiple Hooks. If a custom Hook does not use any hooks internally, it’s not a custom Hook and shouldn’t have the prefix “use”.

We will create a custom Hook called useBoolean which I almost use every time when I join a new project as a React freelancer. But before we implement this hook, let’s see what problem it solves for us. Let’s start with a little example:

javascript
import * as React from 'react';

function App() {
  const [isToggle, setToggle] = React.useState(false);

  const handleToggle = () => setToggle(!isToggle);

  return (
    <div>
      <button type="button" onClick={handleToggle}>
        Toggle
      </button>

      {isToggle.toString()}
    </div>
  );
}

export default App;
false

The component renders a button which toggles a boolean. In a real world React application, there is not much you can do with a stateful boolean. Either you toggle it (like in the previous example) or you set it explicitly to true or false (like in the next example):

javascript
import * as React from 'react';

function App() {
  const [isToggle, setToggle] = React.useState(false);

  const handleToggle = () => setToggle(!isToggle);
  const handleTrue = () => setToggle(true);
  const handleFalse = () => setToggle(false);

  return (
    <div>
      <button type="button" onClick={handleToggle}>
        Toggle
      </button>
      <button type="button" onClick={handleTrue}>
        To True
      </button>
      <button type="button" onClick={handleFalse}>
        To False
      </button>

      {isToggle.toString()}
    </div>
  );
}

export default App;
false

Some developers may argue that we could have used inline handlers instead, so there wouldn’t be the repetitive declaration of event handlers. However, personally I try to avoid inline handlers as much as I can, because they inject too much logic into the JSX which instead should be defined between the component’s function signature and the return statement. But that’s just personal preference.

Anyway, every time you use a stateful boolean, you will encounter the same implementation details: Either you toggle the boolean or set it to one of its two possible values. To shield away this repetitive code when using stateful booleans in more than one React component, I started to create a custom hook for it:

javascript
const useBoolean = () => {
  const [state, setState] = React.useState();

  const handleTrue = () => setState(true);
  const handleFalse = () => setState(false);
  const handleToggle = () => setState(!state);

  return [
    state,
    {
      setTrue: handleTrue,
      setFalse: handleFalse,
      setToggle: handleToggle,
    },
  ];
};

Essentially all implementation details, meaning the state and the event handlers, moved into this custom hook called useBoolean. In addition, the custom hook returns the state and the functions to update the state in an array.

Returning an array is a best practice when returning multiple values from a custom hook, because React’s built-in Hooks — in the case of returning multiple values — make use of arrays and therefore array destructuring as well. Using array destructuring comes with the benefit of giving the destructured values any name (less code than renaming values in the case of object destructuring).

javascript
const useBoolean = (initialState = false) => {
  const [state, setState] = React.useState(initialState);

  const handleTrue = () => setState(true);
  const handleFalse = () => setState(false);
  const handleToggle = () => setState(!state);

  return [
    state,
    {
      setTrue: handleTrue,
      setFalse: handleFalse,
      setToggle: handleToggle,
    },
  ];
};

A good addition would be adding an initial state too (as seen in the last code snippet). Back in our App component, we can make use of this new custom hook by passing an initial state to it and by using its returned values to display the state and to update it:

javascript
function App() {
  const [isToggle, { setToggle }] = useBoolean(false);

  return (
    <div>
      <button type="button" onClick={setToggle}>
        Toggle
      </button>

      {isToggle.toString()}
    </div>
  );
}

Since the custom hook does not only offer the function to toggle the stateful boolean, but also to set it explicitly to true or false, we can make use of these functions too:

javascript
function App() {
  const [isToggle, {
    setToggle,
    setTrue,
    setFalse,
  }] = useBoolean(false);

  return (
    <div>
      <button type="button" onClick={setToggle}>
        Toggle
      </button>
      <button type="button" onClick={setTrue}>
        To True
      </button>
      <button type="button" onClick={setFalse}>
        To False
      </button>

      {isToggle.toString()}
    </div>
  );
}
false

Essentially we extracted the stateful boolean and all the event handlers — which are operating on the boolean — into a custom hook. By using this custom hook every time we need a stateful boolean, we can spare defining the event handlers which include the implementation details about how to manipulate the boolean and instead use the functions that are returned from the hook.

In conclusion, we have learned how to create a custom hook by using one of React’s built-in Hooks called useState. This custom hooks is not complex, however, it should show you how you can either reduce complexity and redundancy in your React project.


There are many custom React Hooks out there suited for various problems. Most of them can be installed via npm. However, whenever I find a good one myself, I try to write briefly about it. These are some of them you may want to check out:

Never Miss an Article

Join 50,000+ developers getting weekly insights on full-stack engineering and AI.

AI Agentic UI Architecture React Next.js TypeScript Node.js Full-Stack Monorepos Product Engineering
Subscribe on Substack

High signal, low noise. Unsubscribe at any time.