Build a React JS Interactive Simple Interactive Component: A Basic Expense Tracker

Managing finances can feel like navigating a maze, and keeping track of expenses is often the first, and most important, step. Whether you’re a student, a freelancer, or simply someone looking to gain better control of your spending, a simple expense tracker can be an incredibly valuable tool. In this tutorial, we’ll build a basic expense tracker using React JS. This project will not only help you understand fundamental React concepts but also equip you with a practical application to manage your finances more effectively. We’ll cover everything from setting up the project to handling user input and displaying data. By the end, you’ll have a functional expense tracker and a solid foundation in React development.

Why Build an Expense Tracker with React?

React is a powerful JavaScript library for building user interfaces. It’s known for its component-based architecture, which makes it easy to create reusable UI elements. Building an expense tracker with React offers several advantages:

  • Component Reusability: You can create components for different parts of your tracker, such as expense entries, input forms, and summary displays, and reuse them throughout your application.
  • Efficient Updates: React efficiently updates the DOM (Document Object Model) only when necessary, leading to a smoother user experience.
  • Data Management: React simplifies data management with its state and props mechanisms, making it easier to handle user input and display data dynamically.
  • Community and Ecosystem: React has a large and active community, providing ample resources, libraries, and support.

This project is perfect for beginners because it introduces core React concepts in a practical and understandable way. You’ll learn about components, state management, event handling, and conditional rendering, all while building something useful.

Setting Up Your React Project

Before we dive into the code, let’s set up our React project. We’ll use Create React App, a popular tool that simplifies the setup process. Open your terminal and run the following command:

npx create-react-app expense-tracker

This command creates a new directory called expense-tracker with all the necessary files and dependencies. Once the installation is complete, navigate into the project directory:

cd expense-tracker

Now, let’s start the development server:

npm start

This command will open your app in your web browser, typically at http://localhost:3000. You should see the default React app. Now, let’s start coding our expense tracker!

Building the Expense Entry Component

The first component we’ll create is the ExpenseEntry component. This component will represent a single expense item, displaying the description, amount, and date. Create a new file named ExpenseEntry.js inside the src directory and add the following code:


import React from 'react';

function ExpenseEntry({ description, amount, date }) {
  return (
    <div className="expense-entry">
      <p><b>Description:</b> {description}</p>
      <p><b>Amount:</b> ${amount}</p>
      <p><b>Date:</b> {date}</p>
    </div>
  );
}

export default ExpenseEntry;

In this code:

  • We import React.
  • We define a functional component called ExpenseEntry that accepts three props: description, amount, and date.
  • The component renders a div with the class name expense-entry containing the expense details.

Now, let’s add some basic styling to our ExpenseEntry component. Create a new file named ExpenseEntry.css in the src directory and add the following CSS:


.expense-entry {
  border: 1px solid #ccc;
  padding: 10px;
  margin-bottom: 10px;
  border-radius: 5px;
}

Finally, import the CSS file into your ExpenseEntry.js file:


import React from 'react';
import './ExpenseEntry.css';

function ExpenseEntry({ description, amount, date }) {
  return (
    <div className="expense-entry">
      <p><b>Description:</b> {description}</p>
      <p><b>Amount:</b> ${amount}</p>
      <p><b>Date:</b> {date}</p>
    </div>
  );
}

export default ExpenseEntry;

Creating the Expense Form Component

Next, we’ll create the ExpenseForm component, which will allow users to add new expense entries. Create a new file named ExpenseForm.js inside the src directory 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 = {
      description: description,
      amount: parseFloat(amount),
      date: date,
    };
    onAddExpense(newExpense);
    setDescription('');
    setAmount('');
    setDate('');
  };

  return (
    <form onSubmit={handleSubmit} className="expense-form">
      <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;

In this code:

  • We import useState from React.
  • We define a functional component called ExpenseForm that accepts a prop called onAddExpense, a function to handle adding new expenses.
  • We use useState to manage the input values for description, amount, and date.
  • The handleSubmit function prevents the default form submission behavior, validates the input, creates a new expense object, calls the onAddExpense function, and clears the input fields.
  • The component renders a form with input fields for description, amount, and date, and a submit button.

Let’s add some basic styling to our ExpenseForm component. Create a new file named ExpenseForm.css in the src directory and add the following CSS:


.expense-form {
  display: flex;
  flex-direction: column;
  max-width: 400px;
  margin: 20px auto;
  padding: 20px;
  border: 1px solid #ddd;
  border-radius: 5px;
}

.expense-form div {
  margin-bottom: 10px;
}

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

.expense-form input {
  width: 100%;
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-sizing: border-box;
}

.expense-form button {
  background-color: #4CAF50;
  color: white;
  padding: 10px 15px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
}

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

Import the CSS file into your ExpenseForm.js file:


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

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 = {
      description: description,
      amount: parseFloat(amount),
      date: date,
    };
    onAddExpense(newExpense);
    setDescription('');
    setAmount('');
    setDate('');
  };

  return (
    <form onSubmit={handleSubmit} className="expense-form">
      <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;

Integrating the Components in App.js

Now, let’s integrate these components into our main App.js file. This file will be the parent component that manages the state of our expense entries and renders the ExpenseForm and ExpenseEntry components. Open App.js in the src directory and replace the existing code with the following:


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

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

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

  return (
    <div className="app">
      <h2>Expense Tracker</h2>
      <ExpenseForm onAddExpense={addExpense} />
      <div className="expense-list">
        {expenses.map((expense, index) => (
          <ExpenseEntry key={index} description={expense.description} amount={expense.amount} date={expense.date} /
        ))}
      </div>
    </div>
  );
}

export default App;

In this code:

  • We import useState, ExpenseEntry, ExpenseForm, and a CSS file.
  • We define a functional component called App.
  • We use useState to manage the expenses array, which holds our expense entries.
  • The addExpense function updates the expenses state when a new expense is added.
  • We render the ExpenseForm component, passing the addExpense function as a prop.
  • We map over the expenses array and render an ExpenseEntry component for each expense item.

Let’s add some basic styling to our App component. Create a new file named App.css in the src directory and add the following CSS:


.app {
  font-family: sans-serif;
  text-align: center;
  padding: 20px;
}

.expense-list {
  margin-top: 20px;
}

Testing Your Expense Tracker

Now, let’s test our expense tracker. Run your React app using npm start in your terminal. You should see the expense tracker in your browser. Enter some expenses using the form and click “Add Expense.” You should see the expenses displayed below the form. If you encounter any issues, double-check your code against the examples provided and ensure you’ve installed all the necessary dependencies.

Common Mistakes and How to Fix Them

As you build your expense tracker, you might encounter some common mistakes. Here are a few and how to fix them:

  • Not importing components correctly: Make sure you correctly import your components at the top of your files. For example, import ExpenseEntry from './ExpenseEntry';
  • Incorrect prop names: Double-check that you’re passing the correct props to your components and using them correctly within the components.
  • State not updating correctly: When updating state, use the correct setter functions provided by useState (e.g., setExpenses). Also, remember to include the spread operator (...) when updating arrays to avoid overwriting existing data.
  • Typographical errors: Carefully check your code for any typos, as they can cause unexpected behavior.
  • Missing dependencies: Ensure that you have installed all the required dependencies. If you’re unsure, you can always run npm install in your project directory to install any missing dependencies.

Adding Features and Enhancements

Once you’ve built the basic expense tracker, you can add many features to enhance its functionality and user experience:

  • Expense Categories: Add a dropdown or input field to categorize expenses (e.g., food, transportation, housing).
  • Date Formatting: Use a library like date-fns to format the date in a user-friendly format.
  • Expense Summary: Calculate and display the total expenses or expenses by category.
  • Data Persistence: Store expense data in local storage or a backend database to persist data across sessions.
  • Editing and Deleting Expenses: Implement functionality to edit or delete existing expense entries.
  • Filtering and Sorting: Add features to filter expenses by date range or category, and sort expenses by amount or date.
  • Responsive Design: Make the app responsive to work well on different screen sizes.
  • Charts and Visualizations: Integrate charting libraries (e.g., Chart.js) to visualize expense data.

Key Takeaways

Building an expense tracker with React offers valuable insights into React development. You’ve learned about components, state management, event handling, and conditional rendering. You’ve also gained practical experience building a functional application that can be extended to meet your specific needs. By understanding these core concepts, you’re well-equipped to tackle more complex React projects.

Frequently Asked Questions (FAQ)

  1. How do I handle form validation in React?

    You can handle form validation by checking the input values when the form is submitted. In the ExpenseForm component, we validated the input fields before adding the expense. You can add more complex validation logic as needed.

  2. How can I store the expense data permanently?

    You can use local storage, a browser feature, to store data. Alternatively, for more complex applications, you can use a backend database (e.g., Firebase, MongoDB) to store the data and retrieve it when the app loads.

  3. How do I add expense categories?

    You can add a select dropdown for categories to your ExpenseForm component and add a category property to your expense objects. Then, you can filter and display expenses based on the selected category.

  4. Can I use this expense tracker on my phone?

    Yes, you can use the expense tracker on your phone, but it will work best if you make the app responsive by using CSS media queries or a responsive CSS framework.

This tutorial has provided a starting point for building a functional expense tracker. Remember that the journey of a thousand miles begins with a single step. As you continue to experiment with React, you’ll discover more advanced techniques and build more sophisticated applications. The goal is to build, learn, and iterate. Keep practicing, and you’ll find yourself creating more complex and useful applications with ease. The knowledge gained from this project serves as a solid base for future React endeavors, paving the way for more intricate and refined applications. With each line of code, you’re not just building a product, but also refining your skills and expanding your understanding of this powerful JavaScript library. Embrace the learning process, and enjoy the journey of becoming a proficient React developer.