How to build a simple counter and a vending machine app with React hooks
Tags: javascript, react, webdev, showdev
Published: 2019-07-08 18:48:26

Today I will introduce to you what many would argue is the shiniest new feature of the popular React library - React Hooks.

I personally am falling in love with the [**React.memo**](https://reactjs.org/docs/react-api.html#reactmemo) concept, but we can reserve it for another tutorial though.

We are here to talk about Hooks so let's get into it.

### First thing first what are hooks??

Fair question. Components are at the heart of the React library and there are essentially two ways to write them. Either as a **class base component** or a **functional component**.

Prior to version **16.8** I believe, using the class base syntax was the only way to tap in into the **component life cycle methods** and also the only way to directly access the very important **state** object.

The workaround or status-quo was to wrap the functional component inside a class component and have it pass the state as **props**.

With the addition of hooks, that is no longer necessary since functional components are now literally able to "hook into" the React exposed methods such as **useState** and **useEffect** which we are going to look into extensively.

Now that we have that out of the way, let's see it in code

### A simple counter

Let's put together our example functional component. The user interface is two buttons in charge of incrementing or decrementing a count value that defaults to 0.

The code below is one of the ways we could go about it

```javascript
import React, { useState } from "react";
import { render } from "react-dom";
import "./styles.css";

const Counter = () => {
  const [count, setCount] = useState(0);
  return (
    <div id="counter">
      <div id="wrapper"> </div>
      <header id="counter-header">
        <div id="header-wrapper"> </div>
        // The fun stuff
        <button
          className="cbtn" onClick={e => {
            if (count > 0) setCount(count - 1);
          }}
        >
         -
        </button>
        <h1>Simple Counter </h1>
        <button
          className="cbtn" onClick={e => {
            setCount(count + 1);
          }}
        >
        +
        </button>
      </header>
      <p className="count">{count} </p>
      <p className="label">Off the hooks!!! </p>
    </div>
  );
};

render(<Counter />, document.getElementById("root"));
```

Just like we would've imported **Component** on the opening line, we are instead adding the **useState hook**. Then a destructuring like statement is used to set the internal state

```javascript
const [count, setCount] = useState(0);
```

The first variable - **count,** on the construct is the **value** and the second **setCount** is the name of the function you will later use to update the value - you can call it whatever you see fit.

Finally, **useState** on the right of the statement takes what looks like an argument but is actually initial value of the state key. 

So in plain English:

> Using the state hook, create a variable named count and associate a function named setCount that will be in charge of updating the value of it. In the meantime, set the initial value of count to 0

We then add event listeners on the buttons and for each we make use of the **setCount ** to update the **count ** value accordingly

```html
 <button className="cbtn" onClick = {(e) => { if(count> 0) setCount(count - 1)}}>
-
 </button>

 <h1>Simple Counter </h1>

 <button className="cbtn" onClick = {(e) => { setCount(count + 1)}}>
+
 </button>
```

![React simple counter](https://techlabs28.com/wp-content/uploads/2019/07/react-counter.gif")

There you have it for a simple example :) Now let's look at something more involved that will allow us to take advantage of a few lifecycle methods inside a functional component

### A Vending Machine

If you have read some of my articles, you might've come across my **[JavaScript - 28 relevant questions series](https://adyngom.github.io/28-relevant-js-questions/toc.html).**

One of the challenges is to build a "simplified" Vending Machine.

You can read more about and definitely take a stab at it following the link below.

[# 6 Vending Machine - 
Bob runs a successful Vending Machine business. He wants to add an interface ...](https://adyngom.github.io/28-relevant-js-questions/6-vending-machine.html)

One of the solution that I have devised for it uses a function as a module. We will import that inside a React functional component and use it to update various states of the application

The complete code can be found here: [React vending machine with hooks](https://stackblitz.com/edit/react-ruhwvv") but let's quickly go step by step. 

Let's first look at our Vending Machine module

```javascript
export default function VendingMachine(inventory) {
  var drinks = inventory || null;

  if (!drinks) {
    throw new Error("No inventory: Cannot add a new VM");
  }

  const drinksKeys = Object.keys(drinks);

  var sale = function(pid) {
    if (!drinks[pid]) {
      return;
    }

    if (drinks[pid].stock > 0) {
      drinks[pid].stock--;
      return `1 ${drinks[pid].name} - Thank you, come again!!`;
    } else {
      drinks[pid].stock = 0;
      return ` ${drinks[pid].name} is out of stock :( Come back tomorrow`;
    }
  };

  var stock = function() {
    const total = drinksKeys.reduce((c, n) => c + drinks[n].stock, 0);
    return total;
  };

  return Object.freeze({ sale, stock });
}
```

The Vending Machine exposes two public methods **sale ** and **stock. ** It also needs to be passed an inventory object that looks like this

```json
{
  "1": {
    "name": "Mango Juice",
    "stock": 2
  },
  "2": {
    "name": "Banana Smoothies",
    "stock": 2
  },
  "3": {
    "name": "Guava Mix",
    "stock": 1
  },
  "4": {
    "name": "Citrus Blend",
    "stock": 3
  }
}
```

Let's assume that this object is coming from an HTTP call. In a class based component scenario, we would have probably use the **ComponentDidMount** lifecycle method to make the request and update the state. In the case of the functional component we will hook into the **useEffect** method to do so.

Now let's set a few rules/goals that we want our React component to do:

- The UI should only render when the VM has been properly set with a valid inventory
- The component will need to make an HTTP request call to get that initial inventory
- The UI will show a loading state until it is ready to render the VM
- Once loaded, each drink from the inventory will be represented by a button.
- Clicking on any of the drinks button will trigger the VM sale method call and displaying either a successful sales or an out of stock message
- The UI will display the starting stock and that number will be updated each time a successful sale is made

#### 1. Initial setup

Let's put the initial wrapper for our little app

```javascript
import React, { Fragment, useState, useEffect } from "react";
import { render } from "react-dom";
import VendingMachine from "./FunModules/VendingMachine";

const LocalVM = () => {
  // functional logic here
  return <Fragment>// view logic here</Fragment>;
};

render(<LocalVM />, document.getElementById("root"));
```

As we did with the Simple Counter, we are importing **useState** but also **useEffect** and **[Fragment](https://reactjs.org/docs/fragments.html)**.

My personal like on **Fragment** is how easy it let us choose if we want add additional tags to the DOM or not - very powerful.

The last import line simply get us our **VM module**. Whether I work on an Angular or React project, I usually create a folder of utilities with pure Vanilla JS that are easy to reuse in either framework or library.

#### 2. Declaring our State(s)

The state syntax in a class component is a key value object. We could definitely repeat that same pattern here, but what it is very interesting and flexible with the **useState ** hook is that you could set each individual state you want to track.

Let's illustrate that in our functional logic section

```javascript
// functional logic here
const [vm, setVM] = useState({});
const [loading, isLoading] = useState(true);
const [data, setData] = useState({});
const [message, setMessage] = useState("...");
const [stock, setStock] = useState(0);
```

I really like how this reads, it is almost self-documenting and probably easy to figure out what each of these does. Let me know if you don't agree :) 

To be crystal clear though, this is what each will handle:

1. **vm** will be the local instance of our Vending Machine and starts as an empty object
2. **loading** is a boolean that defaults to true and will be false when the VM UI is ready to be rendered
3. **data** is the inventory object that we will get back from our HTTP request call
4. **message** is going to be use to display a success or out of stock status
5. and finally **stock** will display the initial count of the total inventory of drinks and update that number anytime a purchase is made

#### 3. Requesting the inventory

Now comes the fun part where we get to take advantage of **useEffect** to wrap around our HTTP request.

```javascript
useEffect(
  () => {
    fetch("https://my-json-server.typicode.com/adyngom/vmapi/db")
      .then(response => response.json())
      .then(data => {
        setData(data);
        setVM(VendingMachine(data));
        isLoading(false);
      });
    // return function statement when component unmounts
  },
  [] // empty array as second argument to ensure the effect runs once
);
```

The hook wraps our **fetch** call and once we get a response, **setData** updates the **data** state and **setVM** attaches an instance of the VendingMachine with the new inventory to our **vm** state.

Please note that we haven't added error handling on our **fetch** call for brevity.

The code adds two very important comments that touch on lifecycle management. It is extremely important to understand that **useEffect** is the equivalent of **ComponentDidMount, ComponentDidUpdate and ComponentWillUnmount** lifecycle methods combined

If we don't pass the empty array as a second argument, the **"effect"** will run every single time the component gets updated. 

That would be great for certain use cases, but in this particular one , we would be telling our component to go fetch and setup a Vending Machine every single time something gets updated in the UI.

The empty array as second argument helps us prevent that by making it a **one and done deal.**

The commented out **return function statement** is a placeholder of where you would put your code if you wanted to do operations when the component **unmounts**.

Think about use cases such as removing event listeners, unsubscribing from an observable etc...

I highly recommend to read more about those on the [React documentation page](https://reactjs.org/docs/hooks-effect.html).

#### 4. Rendering the UI at last

Now that most of our logic is taken care of, we can focus on putting the meat of the component on the page. If we have received **data ** from our fetch call, this will mean that the **loading** state has finished and is now false.

Using the ternary operator, we could compose our view like below

```javascript
return (
  <Fragment>
    {loading ? (
      <p>loading... </p>
    ) : (
      <div>// loading is done put the VM interface here</div>
    )}
  </Fragment>
);
```

Let's also add two helpers function just before the **useEffect** block that will allow for a clean way to call on the **sale** and **stock** methods of the VM

```javascript
const sale = pid => {
  return vm.sale(pid);
};

const getStock = () => {
  return vm.stock();
};
```

With everything in place, let's add the final piece of the UI inside the falsy section
of the ternary statement

```javascript
return (
  <Fragment>
    {loading ? (
      <p>loading... </p>
    ) : (
      <div>
        <h3>Pick a fresh drink and enjoy </h3>
        <p>{message} </p>
        <br />
        <div>
          {Object.keys(data).map(d => {
            return (
              <button
                key={d}
                id={d}
                onClick={e => {
                  setMessage(sale(e.target.id));
                }}
              >
                {data[d].name}{" "}
              </button>
            );
          })}
          <br /> <br />
          <small>VM current stock: {getStock()} </small>
        </div>
      </div>
    )}
  </Fragment>
);
```

So if we are going from top to bottom on the last block we are essentially:

- Putting a reactive **message** string. This gets updated anytime we click on one the buttons which come next
- Using the **data** object we cycle through the **keys** and dynamically build our buttons UI.
- Each button gets an event listener attached to it and will pass the purchased id or **pid** to the local **sale** function.
- The action is wrapped in a **setMessage** call that updates our **message** string with proper success or out of stock string
- Finally **getStock** will be called initially and anytime the component updates to give the updated value of the stock count

#### 5. Let's see it in action

![react vending machine](https://techlabs28.com/wp-content/uploads/2019/07/react-vm-compressor.gif)

And if you do have the **[React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en)** extension installed here is a very slick representation of our UI inside the React DOM

![Local Vending Machine in React DOM With the state and effect hooks](https://adyngom.com/wp-content/uploads/2019/07/screams-2019-07-05-at-8.30.26-PM-1024x576.jpg)

### Conclusion

I've warned you or at least I've tried in the title to tell you that this was going to be lengthy. If you've made it this far though, I hope that like myself you have learned a thing or two about this fascinating way of composing slick UIs with the React library.

The **effect** and **state** hooks, are most likely to be the most prominent ones for many of the use cases in a functional component. But don't cut yourself short by limiting yourself to those two.

I cannot recommend enough this gem of an article by **[Aayush Jaiswal](https://blog.bitsrc.io/@aayush1408)**: 
[10 React Hooks you Should Have in Your Toolbox](https://blog.bitsrc.io/10-react-custom-hooks-you-should-have-in-your-toolbox-aa27d3f5564d)

**[Antonin Januska](https://antjanus.com/about-aj/)** has also put together a nice Hooks cheat sheet:
[The Definitive React Hooks Cheatsheet](https://antjanus.com/blog/web-development-tutorials/front-end-development/the-definitive-react-hooks-cheatsheet)

If you create bits of reusable code, you could definitely take a stab at creating some custom hooks and share with the rest of us. The React docs are surely a great place to start:
[Building Your Own Hooks](https://reactjs.org/docs/hooks-custom.html)

In the end, don't forget to pace yourself. Some are pretty intuitive and straightforward and some might take a few head scratches.

Thanks for reading this far and don't forget to "hook" a few friends up by sharing the article ;)