Custom React Hooks: useBoolean
Tags: react, javascript, programming
Published: 2021-10-05 19:18:39

React hooks initially allow you to "hook into" React state and lifecycle features, like we used to do with the `componentDidMount` or `componentWillUnmount` methods when using class based components. What we'll discover in this article is that we can implement our own custom hooks, using the few primitives hooks React provides us, like `useState` and `useEffect`. This way, you can drastically reduce the cognitive complexity of your components, by moving away some logic into functions that you will be able to reuse anywhere in the other components of your React applications. Your code will look cleaner, and you're following the Single Responsibility Principle (SRP), which states that each class or function (or, in our case, component) should have responsibility over a single part of a program's functionality, and it should encapsulate that part.

Enough talk, let's get to work and implement our first custom hook: `useBoolean`! 😎

## Motivation

First of all, why are we going to implement such a hook? Let's have a look at this simple component:

```jsx
const Spoil = ({ content }) => {
  const [showSpoil, setShowSpoil] = useState(false);

  return (
    <div className="spoil">
      <button onClick={() => setShowSpoil((visible) => !visible)}>
        {showSpoil ? "Hide" : "Show"}
      </button>
      {showSpoil && <div className="spoil-content">{content}</div>}
    </div>
  );
};
```

The component receives a `content` prop, that only appears once the button gets clicked to show the spoil. Of course, clicking the button again will hide it back, and so on.

Here, the component is so simple that it is very easy to read, but we could improve its readability by extracting the button `onClick` listener to a separate function:

```jsx
const Spoil = ({ content }) => {
  const [showSpoil, setShowSpoil] = useState(false);

  const toggle = () => setShowSpoil((visible) => !visible)

  return (
    <div className="spoil">
      <button onClick={toggle}>
        {showSpoil ? "Hide" : "Show"}
      </button>
      {showSpoil && <div className="spoil-content">{content}</div>}
    </div>
  );
};
```

That's better. We've simplified the return value of our function, but we've added a new line between the state initialization and the return statement. Of course this is not a major problem in our case, but when dealing with more complex components, this can lead to redundant functions declarations.

In fact, our component could be further simplified if we had a `useBoolean` hook, that we would use like this:

```jsx
const Spoil = ({ content }) => {
  const [showSpoil, setShowSpoil] = useBoolean(false);

  return (
    <div className="spoil">
      <button onClick={setShowSpoil.toggle}>
        {showSpoil ? "Hide" : "Show"}
      </button>
      {showSpoil && <div className="spoil-content">{content}</div>}
    </div>
  );
};
```

See? We didn't add any extra function, and the `onClick` listener is easier to read. Now, let's move into the implement of this simple hook, shall we? 😎

## Implementation

First, we define a function in which we can use the `useState` hook.

```jsx
const useBoolean = (initialValue) => {
	const [value, setValue] = useState(initialValue)

	return [value, setValue]
}
```

> ⚠️ Be careful: you'll only be able to use the `useBoolean` function (or should I say hook) in React components, as it uses the `useState` hook.

So far, we've just created an alias for the `useState` hook. 

Not very useful...😅

The interesting part comes now: instead of having the `setValue` function in the return array, we will use an object that will contain 3 methods:

- `toggle()` to toggle the value
- `on()` to set the value  to `true`
- `off()` to set the value to `false`

Our hook now looks like this:

```jsx
const useBoolean = (initialValue) => {
	const [value, setValue] = useState(initialValue)

	const updateValue = useRef({
		toggle: () => setValue(oldValue => !oldValue),
		on: () => setValue(true),
		off: () => setValue(false)
	})

	return [value, updateValue.current]
}
```

And here it is, you've just created your first custom hook, congratulations! 🥳

## Usage

```jsx
const Articles = () => {
  const [articles, setArticles] = useState([])
	const [isLoading, setIsLoading] = useBoolean(false)
	const [isError, setIsError] = useBoolean(false)

	useEffect(() => {
		setIsLoading.on()
		fetch(...)
			.then(res => res.json())
			.then(setArticles)
			.catch(setIsError.on)
			.finally(setIsLoading.off)
  }, [])

	return ...
}
```

> ⚠️ Be careful: you can't use `setIsLoading(true)` as we don't export a function anymore but an object.

See how the above snippet is very easy to read? 😎

## Conclusion

Thanks for reading me. I hope you enjoyed this article, and if that's the case, don't hesitate to have a look at my other ones. Also, feel free to post some comments if you have any questions, or if you just want to say "hi". 👋

---

## Support Me

If you wish to support me, you can buy me a coffee with the following link (I will then probably turn that coffee into a new custom hook... ☕)

[![Buy Me A Coffee](https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png)](https://www.buymeacoffee.com/iamludal)

---

## References

[https://reactjs.org/docs/hooks-overview.html](https://reactjs.org/docs/hooks-overview.html)

[https://en.wikipedia.org/wiki/Single-responsibility_principle](https://en.wikipedia.org/wiki/Single-responsibility_principle)