Custom React Hooks: useCounter
Tags: react, javascript, programming
Published: 2021-10-10 13:18:09

In the last article of the [Custom React Hooks series](https://dev.to/iamludal/series/14964), we've implemented the [useBoolean](https://dev.to/iamludal/react-custom-hooks-useboolean-3m6c) hook. Today, we'll create a not more complicated one: `useCounter`. As its name suggests, this hook will help us manage a counter state thanks to utility functions, such as `increment` and `decrement`. Ready? Let's jump right into it! 🚀

## Motivation

As always, let's see why would you want to implement this hook. Imagine you are building an e-commerce website. Whenever a customer wants to buy an item, he should be able to select the quantity he wants. This is how the user interface might look like (let's forget the style):

![UI](https://cdn.hashnode.com/res/hashnode/image/upload/v1633869919339/RLNAmwg8y.png)

And the source code of the `Cart` component might look like this:

```jsx
const Cart = () => {
  const [quantity, setQuantity] = useState(0);

  return (
    <div className="Cart">
      <h1>My Cart</h1>
      <Item
        label="My awesome item"
        quantity={quantity}
        onIncrement={() => setQuantity((q) => q + 1)}
        onDecrement={() => setQuantity((q) => q - 1)}
        onReset={() => setQuantity(0)}
      />
    </div>
  );
}
```

> ℹ️ Of course, all the examples and code snippets will be extremely simplified in order to only focus on what matters the most in this article.

The above component could be simplified by introducing a custom `useCounter` hook:

```jsx
function Cart() {
  const quantity = useCounter(0);

  return (
    <div className="Cart">
      <h1>My Cart</h1>
      <Item
        label="My awesome item"
        quantity={quantity.value}
        onIncrement={quantity.increment}
        onDecrement={quantity.decrement}
        onReset={quantity.reset}
      />
    </div>
  );
}
```

Sounds interesting? Let's implement this hook! 😎

## Implementation

Our `useCounter` hook will have a state to hold the counter value. It will also have 3 methods to update its value: `increment`, `decrement`, and `reset`. With this in mind, we can create the hook in the following way:

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

  const increment = () => setValue(c => c + 1);
  const decrement = () => setValue(c => c - 1);
  const reset = () => setValue(initialValue);

  return { value, increment, decrement, reset };
};
```

Now, some of you might wonder why the 3 exported methods are not wrapped into the `useCallback` hook (which prevents creating new functions at every render, more info [here](https://dmitripavlutin.com/dont-overuse-react-usecallback/#2-the-purpose-of-usecallback)). In our case, the component is so simple that calling `useCallback` 3 times to improve performances could have the opposite effect. This hook should be used when you know your function will be used in a more complex component, for instance one that holds a big list of items, each one using your function as an `onClick` event.

> ℹ️ For more information, don't hesitate to have a look at [this article](https://dmitripavlutin.com/dont-overuse-react-usecallback) from [Dmitri Pavlutin](https://dmitripavlutin.com/), which goes into details about why, when and how to use the `useCallback` hook. The same applies for `useMemo` and `useRef` (except when used as a reference to an element).

That being said, our new custom hook is now ready to use! 🥳

## Improvement ideas

To go further, here are some ideas for improvement to enhance the `useCounter` hook. Don't hesitate to try implementing one or more of this ideas, so that you can practice on your own.

- Adding an increment/decrement step (`counter.increment(step)`)
- Adding a min/max value (`useCounter({ min: 0, max: 10, initial: 0})`)
- Manually set the counter value (`counter.set(value)`)

## Conclusion

So far, the custom hooks we've been creating are very simple. In the next articles, we'll start implementing more complex hooks to really help us simplify our components code and avoid code duplication. That being said, thanks for reading me. I hope you enjoyed this article. If you did, don't hesitate to have a look at my other ones. Also, feel free to write some comments if you have any questions or remarks. 🤗

---

**Source Code** available on [CodeSandbox](https://codesandbox.io/s/custom-react-hooks-usecounter-5w9gk?file=/src/hooks/useCounter.ts)

{% codesandbox 5w9gk %}

---

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