Build a Simple React JavaScript Interactive Interactive Expense Tracker: A Beginner’s Guide

Managing finances can be a daunting task. Keeping track of income and expenses, especially in today’s fast-paced world, often feels like a never-ending chore. Spreadsheets can become unwieldy, and existing apps might lack the features you need or feel overly complex. But what if you could create your own, personalized expense tracker tailored to your specific needs? This tutorial will guide you through building a simple, yet functional, expense tracker using ReactJS. This project is perfect for beginners and intermediate developers looking to solidify their React skills while creating something practical and useful.

Why Build an Expense Tracker with React?

ReactJS is a powerful JavaScript library for building user interfaces. It’s component-based architecture, efficient update mechanisms, and extensive ecosystem make it an excellent choice for creating dynamic and interactive web applications. Building an expense tracker with React offers several benefits:

  • Component-Based Structure: React allows you to break down your application into reusable components, making your code organized and maintainable.
  • Interactive User Interface: React’s virtual DOM efficiently updates the UI, providing a smooth and responsive user experience.
  • State Management: React provides mechanisms for managing data and updating the UI when the data changes.
  • Learning Opportunity: Building an expense tracker provides hands-on experience with fundamental React concepts like components, state, props, and event handling.

Project Overview: What We’ll Build

Our expense tracker will be a single-page application (SPA) with the following features:

  • Input Fields: Users will be able to enter the expense description, amount, and date.
  • Expense List: A list displaying all entered expenses.
  • Total Expenses: A running total of all expenses.
  • Clear Functionality: A button to clear all expenses.
  • Basic Styling: We’ll use CSS to make the app visually appealing.

Setting Up Your Development Environment

Before we start coding, let’s set up our development environment. You’ll need the following:

  • Node.js and npm (Node Package Manager): These are essential for managing JavaScript packages and running React applications. You can download them from https://nodejs.org/.
  • A Code Editor: Choose a code editor like Visual Studio Code, Sublime Text, or Atom.
  • A Web Browser: Chrome, Firefox, or any modern web browser will work.

Once you have Node.js and npm installed, open your terminal or command prompt and navigate to the directory where you want to create your project. Then, run the following command to create a new React app using Create React App:

npx create-react-app expense-tracker

This command will create a new directory called expense-tracker with all the necessary files and configurations for a React application. After the installation is complete, navigate into the project directory:

cd expense-tracker

Finally, start the development server:

npm start

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

Project Structure and Core Components

Our expense tracker will consist of a few key components. Let’s outline the project structure and create the necessary files:

  • src/App.js: This is the main component that will orchestrate the entire application.
  • src/components/ExpenseForm.js: This component will handle the input fields for expense details.
  • src/components/ExpenseList.js: This component will display the list of expenses.
  • src/components/ExpenseItem.js: This component will represent a single expense item in the list.
  • src/App.css: This file will contain the CSS styles for the application.

Create these files and directories inside your src directory. Now, let’s start building the components.

Building the ExpenseForm Component

The ExpenseForm component will be responsible for collecting expense data from the user. Open src/components/ExpenseForm.js and add the following code:

import React, { useState } from 'react';

function ExpenseForm({ onAddExpense }) {
  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,
    };
    onAddExpense(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:

  • We import the useState hook to manage the input field values.
  • We define state variables for description, amount, and date.
  • The handleSubmit function is called when the form is submitted. It prevents the default form submission behavior, validates the input, creates a new expense object, calls the onAddExpense function (passed as a prop), and clears the input fields.
  • The form includes input fields for description, amount, and date, each bound to its corresponding state variable.

Building the ExpenseList Component

The ExpenseList component will display the list of expenses. Open src/components/ExpenseList.js and add the following code:

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

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

export default ExpenseList;

Explanation:

  • We import the ExpenseItem component.
  • The ExpenseList component receives an expenses array as a prop.
  • It maps over the expenses array and renders an ExpenseItem component for each expense.
  • Each ExpenseItem receives the expense data and a function to delete the expense as props.

Building the ExpenseItem Component

The ExpenseItem component will display a single expense item. Open src/components/ExpenseItem.js and add the following code:

import React from 'react';

function ExpenseItem({ expense, onDeleteExpense }) {
  const handleDelete = () => {
    onDeleteExpense(expense.id);
  };

  return (
    <li>
      <div>
        <strong>{expense.description}</strong>
      </div>
      <div>
        Amount: ${expense.amount}
      </div>
      <div>
        Date: {expense.date}
      </div>
      <button onClick={handleDelete}>Delete</button>
    </li>
  );
}

export default ExpenseItem;

Explanation:

  • The ExpenseItem component receives an expense object as a prop, containing the expense details.
  • It displays the description, amount, and date of the expense.
  • It includes a delete button that calls the onDeleteExpense function (passed as a prop) when clicked, passing the expense’s ID.

Building the App Component (App.js)

The App component is the main component that brings everything together. Open src/App.js and add the following code:

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

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

  const handleAddExpense = (newExpense) => {
    setExpenses([...expenses, newExpense]);
    setTotalExpenses(totalExpenses + newExpense.amount);
  };

  const handleDeleteExpense = (id) => {
    const updatedExpenses = expenses.filter((expense) => expense.id !== id);
    const expenseToDelete = expenses.find((expense) => expense.id === id);
    const newTotal = totalExpenses - (expenseToDelete ? expenseToDelete.amount : 0);
    setExpenses(updatedExpenses);
    setTotalExpenses(newTotal);
  };

  const handleClearExpenses = () => {
    setExpenses([]);
    setTotalExpenses(0);
  };

  return (
    <div className="container">
      <h2>Expense Tracker</h2>
      <ExpenseForm onAddExpense={handleAddExpense} />
      <div>
        <h3>Expenses</h3>
        <ExpenseList expenses={expenses} onDeleteExpense={handleDeleteExpense} />
        <p>Total Expenses: ${totalExpenses.toFixed(2)}</p>
        <button onClick={handleClearExpenses}>Clear Expenses</button>
      </div>
    </div>
  );
}

export default App;

Explanation:

  • We import the ExpenseForm and ExpenseList components.
  • We use the useState hook to manage the expenses array and totalExpenses.
  • handleAddExpense function: adds a new expense to the expenses array and updates the total expenses.
  • handleDeleteExpense function: removes an expense from the expenses array and updates the total expenses.
  • handleClearExpenses function: clears all expenses and resets the total expenses to zero.
  • The component renders the ExpenseForm, ExpenseList, and displays the total expenses.

Adding Styles (App.css)

To make the application visually appealing, add the following CSS styles to src/App.css:

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

h2, h3 {
  text-align: center;
  color: #333;
}

form {
  margin-bottom: 20px;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 5px;
  background-color: #fff;
}

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;
  font-size: 16px;
}

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

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

li {
  padding: 10px;
  margin-bottom: 5px;
  border: 1px solid #ddd;
  border-radius: 4px;
  background-color: #fff;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

li button {
  background-color: #f44336;
  color: white;
  padding: 5px 10px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
}

li button:hover {
  background-color: #da190b;
}

Explanation:

  • We define styles for the container, headings, form, labels, input fields, buttons, and list items.
  • These styles will give the expense tracker a clean and organized look.

Finally, import the CSS file into src/App.js by adding the following line at the top of the file:

import './App.css';

Testing and Running Your Application

Now that we’ve built all the components and added styles, it’s time to test and run the application. Make sure your development server is running (npm start). Open your web browser and navigate to http://localhost:3000. You should see your expense tracker application.

Try the following:

  • Enter an expense description, amount, and date, and click the “Add Expense” button. The expense should be added to the list.
  • Add multiple expenses to see them listed.
  • Verify that the total expenses are calculated correctly.
  • Click the “Delete” button next to an expense to remove it.
  • Click the “Clear Expenses” button to clear all expenses.

If everything works as expected, congratulations! You’ve successfully built an expense tracker with ReactJS.

Common Mistakes and How to Fix Them

During development, you might encounter some common mistakes. Here’s a list of potential issues and how to resolve them:

  • Incorrect import paths: Double-check the import paths for your components. Make sure they match the file structure.
  • Uncaught TypeError: This often occurs when you’re trying to access a property of an undefined object. Use the browser’s developer tools (usually accessed by pressing F12) to inspect the error and identify the source.
  • State not updating: Ensure you’re updating the state correctly using the set... functions provided by the useState hook.
  • Prop drilling: If you’re passing props down through multiple levels of components, consider using React Context or a state management library like Redux for more complex applications.
  • CSS not applied: Make sure you’ve imported your CSS file correctly in App.js. Also, check for any typos or CSS specificity issues.

Key Takeaways and Best Practices

Let’s summarize the key takeaways from this tutorial:

  • Component-Based Architecture: React encourages breaking down your UI into reusable components.
  • State Management with useState: The useState hook is fundamental for managing component state.
  • Props for Data Passing: Props allow you to pass data from parent components to child components.
  • Event Handling: React provides a robust event handling system for user interactions.
  • Keep it Simple: Start with a simple project and gradually add features.
  • Testing: Test your components thoroughly to ensure they function as expected.
  • Code Formatting: Use a code formatter like Prettier to maintain consistent code style.
  • Comments: Add comments to your code to explain complex logic or functionality.
  • Error Handling: Implement error handling to gracefully handle unexpected situations.

Enhancements and Next Steps

This expense tracker is a great starting point. Here are some ideas for enhancements and next steps:

  • Add Expense Categories: Allow users to categorize their expenses (e.g., food, transportation, etc.).
  • Implement Filtering: Add filters to view expenses by date range or category.
  • Use Local Storage: Persist the expense data in the browser’s local storage so it doesn’t disappear on refresh.
  • Add Charts and Graphs: Visualize expense data using charts and graphs.
  • Implement User Authentication: Allow users to create accounts and securely store their expense data.
  • Deploy to Production: Deploy your application to a hosting platform like Netlify or Vercel.

FAQ

Here are some frequently asked questions about building an expense tracker with React:

  1. How do I handle form validation?

    You can add validation logic within your handleSubmit function. Check for required fields, data types, and any other constraints. Display error messages to the user if the validation fails.

  2. How do I store the expense data permanently?

    You can use local storage to store the expense data in the browser. Before the component unmounts, serialize the expense data to JSON and save it to local storage. On component mount, retrieve the data from local storage and parse it back into a JavaScript object.

  3. How do I handle date formatting?

    Use a library like date-fns or Moment.js to format the date in a user-friendly format. You can also use the toLocaleDateString() method to format dates. For example: new Date(expense.date).toLocaleDateString()

  4. Can I use a CSS framework?

    Yes, you can use a CSS framework like Bootstrap, Material-UI, or Tailwind CSS to speed up development and provide pre-built components and styles. Install the framework using npm or yarn and import the necessary CSS files into your project.

  5. How do I deploy my React app?

    You can deploy your React app to platforms like Netlify, Vercel, or GitHub Pages. These platforms provide simple deployment processes. You’ll typically need to build your React app (npm run build) and then deploy the contents of the build directory.

Building an expense tracker with React is a rewarding project that allows you to learn and apply fundamental React concepts. By following this guide, you’ve taken the first steps towards creating a practical and useful application. Remember that coding is a journey of continuous learning. Embrace the challenges, experiment with new features, and enjoy the process of building your own applications.