React Tutorial #1: Simple counter using Hooks
Tags: react, javascript, frontend, webdev
Published: 2021-06-01 19:45:57

Hi everybody!

Today, we're going to learn how to create a very basic counter in React using hooks.

Let's assume that, at this point, we all already know the concept of __component__ in React and the fact that every component has _something_ called __state__ that we need to manage in order for our app to work the way we want.

In this post, we'll be covering __useState__ and __useReducer__ hooks. We're going to study two different examples (each of them using a different hook) that will lead to the same result.

With all that said, let's get it started!

##Main idea
The main idea is to create a basic counter that is going to be able to perform the following actions:
1. Adding / subtracting __one single unit__ to / from the total count.
2. Adding / subtracting __an arbitrary quantity__ to / from the total count.

##Structure and styles
We'll be using the same HTML structure and CSS styles for both examples. The structure will basically consist of a total count, some buttons to call a few actions to be performed and an input field to introduce the quantity we want to add or subtract. Rest is just styling to make our counter's interface more user-friendly. But don't you rush. You could play with the code later. 

Now, let's take a look at our counter's functionality.

#Example 1: Using _useState_


###Importing useState
In order to be able to use React hooks, we need to import them. So let's do it.

```jsx
import React, {useState} from 'react';
```


###Setting up the state
First thing that comes into mind when it comes to a counter, is, obviously, the total count. So we need to define it as part of the state and initialize its value to zero.

```jsx
const [count, setCount] = useState(0);
```
>_useState_ returns a stateful value and a function to update it.

Same happens if we're planning to add / subtract an arbitrary quantity to / from the total count. Our app's state should know about that quantity. So, let's make it part of the state as well. Its default value will also be initialized to zero.

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

###Adding functionality
Now that we have defined the state for our app, we can start adding some basic functionality to the counter.


####1. Adding / subtracting one single unit
First thing to remark is that we'll be triggering functionality through __buttons__, which means that these should reference functions to handle the actions that will be performed. We'll use React's _onClick_ event handler for such purpose.

```jsx
<button onClick={handleSubtractOne}>-1</button>
<button onClick={handleAddOne}>+1</button>
```
```jsx
const handleSubtractOne = () => {
   setCount(count - 1);
}
```
```jsx
const handleAddOne = () => {
   setCount(count + 1);
}
```
And that would be it for this basic functionality. Easy, right? Now, let's take a further step.

####2. Adding / subtracting an arbitrary quantity
For implementing this functionality, we'll need an input field to enter the desired quantity and a couple of buttons as well.

```jsx
<input type="text" value={quantity} onChange={handleOnChange} />
```
```jsx
<button onClick={handleSubtractQuantity}>-</button>
<button onClick={handleAddQuantity}>+</button>
```

The _onClick_ event handlers work in the exact same way as the others, with the only distinction that these ones call different handlers (because the functionality they're triggering is different). 

The _onChange_ event handler declared on the input element is used to store the entered value into the state. 

Also note that the value we are passing to the _value_ attribute on the input is the one stored in the state, which will be changing accordingly.

```jsx
const handleOnChange = (e) => {
   setQuantity(e.target.value);
}
```
```jsx
const handleSubtractQuantity = () => {
   if(quantity)
      setCount(count - parseInt(quantity, 10));
}
```
```jsx
const handleAddQuantity = () =>{
   if(quantity)
      setCount(count + parseInt(quantity, 10));
}
```
__Important:__ Since input fields in HTML can't retrieve its value as a number (not even when the input type is set to number, it always takes a _string_ as a value), it's necessary to parse it to _integer_ before using it. Otherwise, it will be concatenated to the current count.

Also note that we're adding a condition to make sure no empty value is added or subtracted, which would result in a _NaN_.

####3. Reseting the counter
Since we want our counter to be the most functional possible, we're going to add a button to reset the counter to zero. Its event handler will reference a function that will just set count and quantity state values to zero.

```jsx
<button onClick={handleResetCounter}>Reset counter</button>
```

```jsx
const handleResetCounter = () => {
   setCount(0);
   setQuantity(0);
}
```
And that's it! Our counter is now ready to use.

Check the full implementation here:
https://codesandbox.io/s/beautiful-mahavira-r1idm

#Example 2: Using _useReducer_
Now, we're going to create the exact same counter but, this time, its functionality will be implemented using React's __useReducer__ hook.


###Importing useReducer
As we did in the other example, we need to import the hook we're going to work with.

```jsx
import React, {useReducer} from 'react';
```

###Setting up the state
For this new case, we're going to set up the state in a slightly different way: we'll specify an initial state and also a _reducer_ function that will take care of all the functionality, as it's required by _useReducer_. Both the initial state and the function will be taken as parameters by this hook.

```jsx
const initialState = {count: 0, quantity: 0};
```

```jsx
const [state, dispatch] = useReducer(reducer, initialState);
```
>_useReducer_ returns the current state and a dispatch method.

###The _reducer_ function
The approach of this hook is to have a reducer function that accepts the state of the app (or component) and an action as parameters, and, based on that action, the state is managed one way or another.

So let's take a look at the reducer function that we'll be using:
```jsx
const reducer = (state, action) => {
  switch (action.type) {
    case "addOne":
      return {...state, count: state.count + 1};
    case "subtractOne":
      return {...state, count: state.count - 1};
    case "addQuantity":
      return {...state, count: state.count + parseInt(state.quantity, 10)};
    case "subtractQuantity":
      return {...state, count: state.count - parseInt(state.quantity, 10)};
    case "setQuantity":
      return {...state, quantity: action.payload};
    case "resetCounter":
      return initialState;
    default:
      throw new Error();
  }
};
```
This function contains all the possible use cases that the counter is able to perform. If the action type passed in doesn't appear in the list of specified functions, an error will be thrown.

__Important:__ Don't forget to spread the state every time you set any of its fields to keep the rest of the values as they are. Otherwise, your stored data will be overwritten with the returned value.

###The handlers
We'll be using the same handlers, but now, they won't update the state values directly using a setter function. Instead, they will dispatch different actions that will return values to _useReducer_, which will handle them properly to update the state. 

_useReducer_ throws actions in the way Redux does, so, if you're familiarized with Redux, you'll find its behavior pretty much the same.


```jsx
const handleSubtractOne = () => {
   dispatch({type: "subtractOne"});
};
```
```jsx
const handleAddOne = () => {
   dispatch({type: "addOne"});
};
```
```jsx
const handleSubtractQuantity = () => {
   if (state.quantity)
      dispatch({type: "subtractQuantity"});
};
```
```jsx
const handleAddQuantity = () => {
   if (state.quantity)
      dispatch({type: "addQuantity"});
};
```
```jsx
const handleResetCounter = () => {
   dispatch({type: "resetCounter"});
};
```
```jsx
const handleOnChange = (e) => {
   dispatch({type: "setQuantity", payload: e.target.value});
};
```

And that's all.

Check the full implementation here:
https://codesandbox.io/s/quizzical-framework-3r2pp

I hope you find this tutorial useful and see you in the next.

____

🎉 Follow me on Instagram and Twitter for more related content: @underscorecode