DEV Community

Cover image for Building a React Expense Tracker App
Abhishek Gurjar
Abhishek Gurjar

Posted on

Building a React Expense Tracker App

Introduction

In this tutorial, we will create an Expense Tracker Web Application using React. This project will help you understand state management, event handling, and dynamic list updates in React. It’s ideal for beginners aiming to strengthen their knowledge of React development by building a practical and useful application.

Project Overview

The Expense Tracker application allows users to keep track of their income and expenses. It helps manage financial data by categorizing and calculating income, expenses, and the total balance. This project showcases the use of React for managing state and handling user input efficiently.

Features

  • Add Transactions: Users can add income or expense transactions.
  • Track Balance: Users can view their total balance and track changes dynamically.
  • Delete Transactions: Users can remove transactions from the list.
  • Local Storage: Transactions are persisted across page reloads using localStorage.

Technologies Used

  • React: To build the user interface and manage component state.
  • CSS: To style the application.
  • JavaScript: To handle the application's core logic.

Project Structure

The project structure follows a typical React project layout:

├── public
├── src
│   ├── components
│   │   ├── TransactionList.jsx
│   │   ├── TransactionItem.jsx
│   │   ├── AddTransaction.jsx
│   ├── App.jsx
│   ├── App.css
│   ├── index.js
│   └── index.css
├── package.json
└── README.md
Enter fullscreen mode Exit fullscreen mode

Key Components

  • TransactionList.jsx: Displays and manages the list of transactions.
  • TransactionItem.jsx: Represents an individual transaction.
  • AddTransaction.jsx: Handles adding new transactions (income or expense).

Code Explanation

TransactionList Component

This component handles displaying the transactions and managing the state of all transactions.

import { useState, useEffect } from "react";
import TransactionItem from "./TransactionItem";

const TransactionList = () => {
  const [transactions, setTransactions] = useState([]);

  useEffect(() => {
    const savedTransactions = JSON.parse(localStorage.getItem("transactions")) || [];
    setTransactions(savedTransactions);
  }, []);

  useEffect(() => {
    localStorage.setItem("transactions", JSON.stringify(transactions));
  }, [transactions]);

  const deleteTransaction = (index) => {
    const newTransactions = transactions.filter((_, i) => i !== index);
    setTransactions(newTransactions);
  };

  return (
    <div className="transaction-list">
      <h2>Transaction History</h2>
      <ul>
        {transactions.map((transaction, index) => (
          <TransactionItem
            key={index}
            transaction={transaction}
            deleteTransaction={deleteTransaction}
          />
        ))}
      </ul>
    </div>
  );
};

export default TransactionList;
Enter fullscreen mode Exit fullscreen mode

TransactionItem Component

The TransactionItem component represents an individual transaction, including options to delete it.

const TransactionItem = ({ transaction, deleteTransaction }) => {
  const sign = transaction.amount < 0 ? "-" : "+";
  return (
    <li className={transaction.amount < 0 ? "expense" : "income"}>
      {transaction.text} 
      <span>{sign}${Math.abs(transaction.amount)}</span>
      <button onClick={deleteTransaction}>Delete</button>
    </li>
  );
};

export default TransactionItem;
Enter fullscreen mode Exit fullscreen mode

AddTransaction Component

This component manages adding new transactions, allowing users to input income or expense data.

import { useState } from "react";

const AddTransaction = ({ addTransaction }) => {
  const [text, setText] = useState("");
  const [amount, setAmount] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();
    const transaction = { text, amount: +amount };
    addTransaction(transaction);
    setText("");
    setAmount("");
  };

  return (
    <div>
      <h2>Add New Transaction</h2>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={text}
          onChange={(e) => setText(e.target.value)}
          placeholder="Enter description"
        />
        <input
          type="number"
          value={amount}
          onChange={(e) => setAmount(e.target.value)}
          placeholder="Enter amount"
        />
        <button type="submit">Add Transaction</button>
      </form>
    </div>
  );
};

export default AddTransaction;
Enter fullscreen mode Exit fullscreen mode

App Component

The App.jsx serves as the root of the application, rendering the TransactionList and AddTransaction components.

import { useState } from "react";
import TransactionList from './components/TransactionList';
import AddTransaction from './components/AddTransaction';
import './App.css';

const App = () => {
  const [transactions, setTransactions] = useState([]);

  const addTransaction = (transaction) => {
    setTransactions([...transactions, transaction]);
  };

  return (
    <div className="app">
      <h1>Expense Tracker</h1>
      <TransactionList transactions={transactions} />
      <AddTransaction addTransaction={addTransaction} />
<div className="footer">
          <p>Made with ❤️ by Abhishek Gurjar</p>
        </div>
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

CSS Styling

The CSS ensures the application looks clean and user-friendly.

body {
  font-family: Arial, sans-serif;
  background-color: #f4f4f4;
}

.app {
  width: 400px;
  margin: 50px auto;
  background-color: #fff;
  padding: 20px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

h1 {
  text-align: center;
}

input {
  width: calc(100% - 10px);
  padding: 5px;
  margin-bottom: 10px;
}

button {
  width: 100%;
  padding: 10px;
  background-color: #007BFF;
  color: #fff;
  border: none;
  cursor: pointer;
}

button:hover {
  background-color: #0056b3;
}

.transaction-list ul {
  list-style: none;
  padding: 0;
}

.transaction-list li {
  background-color: #f9f9f9;
  margin: 5px 0;
  padding: 10px;
  border-left: 5px solid green;
}

.transaction-list li.expense {
  border-left: 5px solid red;
}

.transaction-list span {
  float: right;
}

button {
  float: right;
  background-color: red;
  color: white;
  padding: 5px;
}
.footer{
    text-align: center;
    margin: 40px;
}
Enter fullscreen mode Exit fullscreen mode

Installation and Usage

To get started, clone the repository and install the dependencies:

git clone https://github.com/abhishekgurjar-in/expense-tracker.git
cd expense-tracker
npm install
npm start
Enter fullscreen mode Exit fullscreen mode

The application will start running at http://localhost:3000.

Live Demo

Check out the live demo of the Expense Tracker here.

Conclusion

The Expense Tracker project demonstrates how to manage lists and state effectively in React. It’s a great way to learn how to build dynamic applications with persistent data storage using localStorage.

Credits

  • Inspiration: Built with the idea of helping users track their financial transactions.

Author

Abhishek Gurjar is a dedicated web developer passionate about creating practical and functional web applications. Check out more of his projects on GitHub.

Top comments (0)