Build a Simple Expense Tracker App with React: A Beginner’s Guide

Managing finances can be a daunting task for many, often leading to a lack of clarity on where money is going. Tracking expenses manually, with spreadsheets or notebooks, can be time-consuming and prone to errors. This is where a simple expense tracker app can make a significant difference. By automating the process, users gain real-time insights into their spending habits, enabling better budgeting and financial control. In this tutorial, we will build a basic expense tracker using React JS, a popular JavaScript library for building user interfaces. This project is ideal for beginners and intermediate developers looking to enhance their React skills while creating a practical application.

Why Build an Expense Tracker?

Creating an expense tracker offers several benefits:

  • Practical Application: You create something useful.
  • Skill Development: You practice and master core React concepts.
  • Portfolio Piece: It’s a tangible project to showcase your abilities.
  • Understanding State Management: Learn to manage data within your application.

Prerequisites

Before we begin, ensure you have the following:

  • Basic JavaScript Knowledge: Familiarity with JavaScript fundamentals.
  • Node.js and npm (or yarn) installed: These are essential for managing project dependencies.
  • A Code Editor: Such as VS Code, Sublime Text, or Atom.

Setting Up the React Project

Let’s start by creating a new React project using Create React App. Open your terminal and run the following command:

npx create-react-app expense-tracker
cd expense-tracker

This command creates a new React application named “expense-tracker” and navigates you into the project directory. Next, start the development server:

npm start

This will open the app in your browser, typically at http://localhost:3000. You should see the default React welcome screen.

Project Structure

Before we dive into the code, let’s outline the project structure we’ll be using:

expense-tracker/
├── src/
│   ├── components/
│   │   ├── ExpenseForm.js
│   │   ├── ExpenseList.js
│   │   └── ExpenseItem.js
│   ├── App.js
│   ├── App.css
│   └── index.js
├── public/
│   └── ...
├── package.json
└── ...

We’ll create three main components:

  • ExpenseForm: Handles form input for adding new expenses.
  • ExpenseList: Displays a list of expenses.
  • ExpenseItem: Represents a single expense in the list.
  • App.js: The main component that orchestrates everything.

Building the ExpenseForm Component

First, create a new folder named “components” inside the “src” directory. Inside the “components” folder, create a file named “ExpenseForm.js”. This component will contain the form for adding expenses.

ExpenseForm.js:

import React, { useState } from 'react';

function ExpenseForm({ addExpense }) {
  const [description, setDescription] = useState('');
  const [amount, setAmount] = useState('');
  const [date, setDate] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!description || !amount || !date) {
      alert('Please fill in all fields.');
      return;
    }

    const newExpense = {
      id: Math.random().toString(), // Generate a unique ID
      description,
      amount: parseFloat(amount),
      date,
    };
    addExpense(newExpense);
    setDescription('');
    setAmount('');
    setDate('');
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="description">Description:</label>
        <input
          type="text"
          id="description"
          value={description}
          onChange={(e) => setDescription(e.target.value)}
        />
      </div>
      <div>
        <label htmlFor="amount">Amount:</label>
        <input
          type="number"
          id="amount"
          value={amount}
          onChange={(e) => setAmount(e.target.value)}
        />
      </div>
      <div>
        <label htmlFor="date">Date:</label>
        <input
          type="date"
          id="date"
          value={date}
          onChange={(e) => setDate(e.target.value)}
        />
      </div>
      <button type="submit">Add Expense</button>
    </form>
  );
}

export default ExpenseForm;

Explanation:

  • Import React and useState: Imports the necessary modules.
  • State Variables: Uses `useState` to manage the description, amount, and date input fields.
  • handleSubmit Function: Prevents the default form submission, validates the input, creates a new expense object, and calls the `addExpense` function passed from the parent component. It also clears the form fields after submission.
  • Form Structure: Includes the form elements (description, amount, date), labels, and input fields. The `onChange` event handlers update the state variables as the user types.

Building the ExpenseList Component

Next, create “ExpenseList.js” inside the “components” folder. This component will display the list of expenses.

ExpenseList.js:

import React from 'react';
import ExpenseItem from './ExpenseItem';

function ExpenseList({ expenses }) {
  return (
    <ul>
      {expenses.map((expense) => (
        <ExpenseItem key={expense.id} expense={expense} />
      ))}
    </ul>
  );
}

export default ExpenseList;

Explanation:

  • Import React and ExpenseItem: Imports the necessary modules, including the ExpenseItem component.
  • Expenses Prop: Receives an array of expenses as a prop.
  • Mapping Expenses: Uses the `map` function to iterate over the `expenses` array and render an `ExpenseItem` component for each expense.
  • ExpenseItem Component: Each expense item is rendered using the `ExpenseItem` component, passing the expense data as a prop.

Building the ExpenseItem Component

Create “ExpenseItem.js” inside the “components” folder. This component represents a single expense item in the list.

ExpenseItem.js:

import React from 'react';

function ExpenseItem({ expense }) {
  return (
    <li>
      <div>{expense.description}</div>
      <div>${expense.amount}</div>
      <div>{expense.date}</div>
    </li>
  );
}

export default ExpenseItem;

Explanation:

  • Import React: Imports the necessary module.
  • Expense Prop: Receives a single expense object as a prop.
  • Display Expense Details: Displays the description, amount, and date of the expense within a list item.

Building the App.js Component

Now, let’s modify “App.js” to integrate all the components.

App.js:

import React, { useState } from 'react';
import ExpenseForm from './components/ExpenseForm';
import ExpenseList from './components/ExpenseList';
import './App.css';

function App() {
  const [expenses, setExpenses] = useState([]);

  const addExpense = (newExpense) => {
    setExpenses([...expenses, newExpense]);
  };

  return (
    <div className="container">
      <h2>Expense Tracker</h2>
      <ExpenseForm addExpense={addExpense} />
      <ExpenseList expenses={expenses} />
    </div>
  );
}

export default App;

Explanation:

  • Import Components: Imports `ExpenseForm`, `ExpenseList`, and the `App.css` file.
  • State Management: Uses `useState` to manage the `expenses` array, which holds all the expense data.
  • addExpense Function: This function is passed to the `ExpenseForm` component. It receives a new expense object, and updates the `expenses` state by adding the new expense to the existing array using the spread operator.
  • Rendering Components: Renders the `ExpenseForm` and `ExpenseList` components. The `addExpense` function is passed as a prop to `ExpenseForm`, and the `expenses` array is passed as a prop to `ExpenseList`.

Adding Basic Styling (App.css)

Create an “App.css” file in the “src” directory to add some basic styling to your app.

App.css:

.container {
  max-width: 600px;
  margin: 20px auto;
  padding: 20px;
  border: 1px solid #ccc;
  border-radius: 5px;
  background-color: #f9f9f9;
}

form {
  margin-bottom: 20px;
}

label {
  display: block;
  margin-bottom: 5px;
  font-weight: bold;
}

input[type="text"], input[type="number"], input[type="date"] {
  width: 100%;
  padding: 8px;
  margin-bottom: 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-sizing: border-box;
}

button {
  background-color: #4CAF50;
  color: white;
  padding: 10px 15px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

button:hover {
  background-color: #3e8e41;
}

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

li {
  padding: 10px;
  border: 1px solid #eee;
  margin-bottom: 5px;
  border-radius: 4px;
  background-color: #fff;
}

Running the Application

Save all the files and run the application using `npm start`. You should now see the expense tracker app in your browser. You can enter expense details and add them to the list.

Common Mistakes and How to Fix Them

Here are some common mistakes and how to fix them:

  • Incorrect Import Paths: Double-check your import paths. Ensure that the file paths in your `import` statements are correct. Incorrect paths will result in errors.
  • Unnecessary Re-renders: Avoid unnecessary re-renders by using the `React.memo` higher-order component for functional components or by implementing `shouldComponentUpdate` in class components.
  • Incorrect State Updates: When updating state, ensure you are using the correct syntax. For example, when updating an array, use the spread operator (`…`) to avoid directly mutating the state.
  • Missing Keys in Lists: When rendering lists of components, always provide a unique `key` prop to each element. This helps React efficiently update the DOM.
  • Event Handler Issues: Ensure your event handlers are correctly bound. In functional components, you don’t need to bind `this`, but make sure the event handlers are correctly defined and passed to the appropriate elements.

Enhancements and Next Steps

Once you have the basic functionality working, you can add further enhancements:

  • Expense Deletion: Implement a feature to delete expenses.
  • Expense Editing: Allow users to edit existing expenses.
  • Data Persistence: Store expenses in local storage or a database.
  • Data Visualization: Add charts or graphs to visualize spending patterns.
  • Categorization: Categorize expenses (e.g., food, transportation).
  • Filtering: Implement filtering options (e.g., by date range, category).

Summary / Key Takeaways

In this tutorial, we created a simple expense tracker using React. We covered the basics of setting up a React project, creating components, handling user input, managing state, and rendering lists. This project serves as a solid foundation for understanding React fundamentals and building more complex applications. By following this guide, you should now have a working expense tracker app and a better understanding of how to use React to build interactive user interfaces. Remember to practice, experiment, and explore the advanced features of React to enhance your skills. The key takeaways from this project include:

  • Component-Based Architecture: React applications are built from reusable components.
  • State Management: `useState` is essential for managing component data.
  • Event Handling: Handling user interactions is crucial for creating dynamic apps.
  • Rendering Lists: Efficiently rendering lists using `map` and unique keys.

FAQ

Here are some frequently asked questions:

  1. How do I handle form validation?
    • You can add validation logic within the `handleSubmit` function. Check if the input fields are empty or meet specific criteria (e.g., amount must be a number). Display error messages to the user if validation fails.
  2. How can I store the expenses permanently?
    • You can use local storage to store the expenses in the user’s browser. Use the `localStorage.setItem()` and `localStorage.getItem()` methods. For more advanced storage, you could use a database (e.g., Firebase, MongoDB) and backend (e.g., Node.js, Python).
  3. How do I add categories to expenses?
    • Add a new input field in the `ExpenseForm` for the category. Update the `ExpenseItem` component to display the category. Modify the state in `App.js` to include the category.
  4. What are the benefits of using React?
    • React allows you to create reusable UI components, making it easier to build and maintain complex applications. It uses a virtual DOM, which makes updates faster. It also has a large and active community, providing plenty of resources and support.
  5. How can I deploy this app?
    • You can deploy the app using services like Netlify, Vercel, or GitHub Pages. Build your project using `npm run build`, and then deploy the contents of the “build” folder to your chosen platform.

Building this expense tracker is just the start of your journey. As you explore React further, you’ll discover more advanced features and techniques to create sophisticated and user-friendly applications. Consider adding features like user authentication, data visualization, and more detailed reporting. Remember that the best way to learn is by doing, so continue experimenting and building projects to solidify your skills. Keep practicing, and you will become proficient in React. Every line of code written, every challenge overcome, contributes to your growth. The ability to create something useful from scratch is a rewarding experience, and with each project, you gain confidence and expertise. Embrace the learning process, and enjoy the journey of becoming a skilled React developer.