Inventory tracker app in react

Build an Inventory List with React useState, useEffect, useRef

Web Development

In this React js Project you will learn how to create a inventory tracker app. The inventory tracker is a web-based application that allows users to manage and track the items in their inventory. It is built using the React JavaScript library, which is a popular choice for building user interfaces because of its flexibility and efficiency.

Don’t know React and want a quick tutorial? Then check out my React Crash Course.

Step 1: Setting up the project

Before we can start building the React js Project, we need to set up the project by creating a new React app using the npx create-react-app command. This will generate the necessary files and dependencies for the project, including a development server that we can use to test the app as we build it.

Step 2: Creating the InventoryList component

In order to create your react app, type in to the command line:

npx create-react-app inventory-list

The InventoryList component is the main component of the app, and it is responsible for displaying the list of items, as well as the input fields and buttons that allow users to add, edit, and delete items from the list.

To create the InventoryList component, we start by importing the useState hook from the react library, which allows us to add state to functional components. We then define the InventoryList function and declare several state variables using the useState hook. These state variables include the items array, which will store the list of items; the newItem and newQuantity variables, which will store the values of the input fields; and the currentIndex variable, which will store the index of the item currently being edited.

Next, you need to define several event handler functions that will be called in response to user actions. These include handleItemChange and handleQuantityChange, which will update the newItem and newQuantity state variables when the input fields are changed; handleSubmit, which will be called when the form is submitted and will add a new item to the list or save changes to an existing item; handleDelete, which will delete an item from the list; and handleEdit, which will update the input fields with the values of the item being edited.

Finally, we render the InventoryList component by returning a div element that contains a form element with the input fields and submit button, and an unordered list element that displays the list of items. Each item in the list includes an edit button and a delete button that allow the user to edit or delete the item.

Step 3: Adding CSS styles

To add some basic styling to this React js Project, we can create a separate CSS file and include it in the project. We can then define styles for the various elements in the app, such as the form, input fields, buttons, and list items.



@import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap");

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  text-decoration: none;
  list-style-type: none;
}

/* Roboto Font */
body {
  font-family: "Roboto", sans-serif;
}

/*Container class*/
.container {
  max-width: 900px;
  margin: 0 auto;
}

.d-flex {
  display: flex;
  justify-content: center;
  align-items: center;
}
.d-flex.flex-column {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}
.space-between {
  justify-content: space-between;
}

/* Text Alignment */
.text-left {
  text-align: left;
}

.text-center {
  text-align: center;
}

.text-right {
  text-align: right;
}

/* Margin classes*/
.m-1 {
  margin: 1rem;
}

.m-auto {
  margin: auto;
}
.mx-auto {
  margin: auto 0;
}
.mt-1 {
  margin-top: 1rem;
}

.mb-1 {
  margin-bottom: 1rem;
}

/*Title */
.title {
  font-size: 3.75rem;
  font-weight: 500;
  margin: 3rem 0;
}

/*Main Btn Class*/
.btn,
.btn-primary {
  margin: 0.25rem 0.125rem;
  padding: 0.35rem 1.25rem;
  font-family: inherit;
  font-weight: 500;
  font-size: 1rem;
  letter-spacing: 0.6px;
  border-radius: 0.3rem;
  color: #fff;
  background-color: #000;
  border: none;
  box-shadow: 0 2px 5px rgba(51, 51, 51, 0.3);
  transition: 0.3s ease;
}
.btn:hover,
.btn-danger:hover,
.btn-primary:hover {
  cursor: pointer;
  box-shadow: none;
  transition: 0.3s ease;
  background: rgba(0, 0, 0, 0.75);
}

/* Btn Types*/
.btn-primary {
  background-color: #7633f9;
  color: white;
}
.btn-primary:hover {
  background: rgba(118, 51, 249, 0.75);
}

.btn-danger {
  background-color: #dc3545;
  color: white;
}
.btn-danger:hover {
  background: rgba(220, 53, 69, 0.75);
}

.btn-sm {
  margin: 0.1875rem 0.09375rem;
  padding: 0.2625rem 0.9375rem;
  font-size: 12px;
}

.form-group {
  margin-bottom: 1rem;
}

.form-group input {
  border: 1px solid rgba(238, 238, 238, 0.9333333333);
  border-radius: 5px;
  padding: 0.5rem;
  width: 100%;
}

Step 4. Create a general container

Create a general container for the application which will hold the title of the application, the form with 2 input tags for item name and item quantity with a submit button that will submit the information from the form to the state. The create a output using a ul where you can loop over the list of items stored in the state an output each one of them in a list item containing the item name, item quantity and two buttons, one for editing the name and quantity and a delete button what can permanently delete the app.

 <div className="container">
      <h1 className="title text-center">Inventory List</h1>
      <form
        className="d-flex"
        style={{ justifyContent: "center" }}
        onSubmit={handleSubmit}
      >
        <div className="form-group m-1">
          <input
            placeholder="Item name"
            style={{ border: "1px solid #7633f9" }}
            ref={itemName}
            value={newItem}
            onChange={handleItemChange}
          />
        </div>
        <div className="form-group m-1">
          <input
            placeholder="Item quantity"
            style={{ border: "1px solid #7633f9" }}
            ref={itemQuantity}
            value={newQuantity}
            onChange={handleQuantityChange}
          />
        </div>
        <button className="btn btn-primary" type="submit">
          {currentIndex >= 0 ? "Save" : "Add"}
        </button>
      </form>
      <ul className="container text-left" style={{ width: 420 }}>
        {console.log(items)}
        {items.map((item, index) => (
          <li
            key={index}
            className="d-flex space-between mb-1"
            style={{ borderBottom: "1px solid #333" }}
          >
            {item.item} ({item.quantity})
            <div>
              <button className="btn btn-sm" onClick={() => handleEdit(index)}>
                Edit
              </button>
              <button
                className="btn btn-danger btn-sm"
                onClick={() => handleDelete(index)}
              >
                X
              </button>
            </div>
          </li>
        ))}
      </ul>
    </div>

Step 5. Focus on Form inputs

Focus on input item name by using React useRef and useEffect hooks.

Start by Importing in to this React js Project the useRef and useEffect hooks to your application.

import { useRef, useEffect } from "react";

the useRef hook to create two refs, itemName and itemQuantity, which will be used to reference the input fields in the app. The useEffect hook is then used to focus the itemName input field when the component is rendered.

The useRef hook creates a mutable object that can be used to store a value that persists between renders. In this case, the refs are used to store references to the input fields, which can be accessed using the current property.

The useEffect hook is a way to perform side effects in functional components. It takes a callback function that will be executed after the component has rendered, and an array of dependencies that determines when the callback should be executed. In this case, the callback function focuses the itemName input field, and the empty array of dependencies means that the callback will only be executed once, when the component is first rendered.

 let itemName = useRef();
 let itemQuantity = useRef();

 useEffect(() => {
    itemName.current.focus();
 }, []);

Step 6. Handle the Form submission

The handleSubmit function is an event handler that is called when the form is submitted. It has an event parameter, which is passed to the function automatically when the form is submitted.

The first thing the function does is call event.preventDefault(), which prevents the default behavior of the form submission (which is to reload the page). This allows us to handle the form submission in our own code, rather than relying on the default behavior.

The function then checks the value of currentIndex. If it is greater than or equal to 0, this means that an item is currently being edited. In this case, the function creates a new array called updateItem that is a copy of the items array. It then updates the item at the currentIndex position in the array with the new values of newItem and newQuantity. It then calls the setItems function to update the items state variable with the updated array, and sets currentIndex back to -1 to indicate that no item is currently being edited.

If currentIndex is not greater than or equal to 0, this means that a new item is being added to the list. The function checks whether the itemName and itemQuantity input fields are empty. If either of them is empty, it displays an alert asking the user to add an item name and quantity. If both input fields are filled in, it adds a new object to the items array with the values of newItem and newQuantity, and calls the setItems function to update the state variable.

Finally, the function sets newItem and newQuantity back to empty strings to clear the input fields. This allows the user to add another item to the list if needed.

  function handleSubmit(event) {
    event.preventDefault();
    if (currentIndex >= 0) {
      const updateItem = [...items];
      updateItem[currentIndex] = { item: newItem, quantity: newQuantity };
      setItems(updateItem);
      setCurrentIndex(-1);
    } else {
      if (itemName.current.value === "" || itemQuantity.current.value === "") {
        window.alert("Add item name and quantity");
      } else {
        setItems([...items, { item: newItem, quantity: newQuantity }]);
      }
    }
    setNewItem("");
    setNewQuantity("");
  }

Step 7. Handle form input changes

Next Create functions that handle item name change and the item quantity change

 function handleItemChange(event) {
    setNewItem(event.target.value);
  }
  function handleQuantityChange(event) {
    setNewQuantity(event.target.value);
  }

Step 8. Handle Delete item

The handleDelete function is an event handler that is called when the delete button for a particular item is clicked. It has an index parameter that represents the index of the item in the items array.

The function displays a confirm dialog asking the user if they want to delete the item. If the user clicks “OK”, the function filters the items array and returns a new array that excludes the item at the index position. This is done using the Array.filter() method, which returns a new array containing only the elements that pass a test function. In this case, the test function checks whether the index of the current element in the array is not equal to the index parameter. If it is not equal, this means that the element should be included in the new array, and it is returned. If the index is equal, this means that the element should be excluded, and it is not included in the new array.

The function then calls the setItems function to update the items state variable with the new array. This effectively removes the item from the list.

  function handleDelete(index) {
    window.confirm("Delete item?") &&
      setItems(items.filter((item, i) => i !== index));
  }

Step 9. Handle Edit item

The handleEdit function is an event handler that is called when the edit button for a particular item is clicked. It has an index parameter that represents the index of the item in the items array.

The function first calls the setCurrentIndex function to update the currentIndex state variable with the value of the index parameter. This is used to track which item is currently being edited.

The function then uses destructuring to extract the item and quantity properties from the object at the index position in the items array. It then calls the setNewItem and setNewQuantity functions to update the newItem and newQuantity state variables with these values, respectively.

This allows the input fields in the form to be pre-populated with the values of the item that is being edited, so that the user can make changes to the item name and quantity and submit the form to update the item in the list.

 function handleEdit(index) {
    setCurrentIndex(index);
    const { item, quantity } = items[index];
    setNewItem(item);
    setNewQuantity(quantity);
  }

Conclusion

The inventory tracker app is a useful tool for managing and tracking items in an inventory. It is easy to use and allows users to quickly add, edit, and delete items from the list. With a little bit of customization, it can be tailored to fit the specific needs of any inventory management system.

Hope you enjoyed this React js Project!

For more information check out the complete video tutorial on YouTube.

Watch the full tutorial on YouTube and get step by step excellent education information about this project.

Want to become a web developer ?

Get complete web development courses on HTML, CSS , JavaScript, Bootstrap, Visual Studio Code, Responsive design and much more…

Love Podcast about web development?

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.