In the fast-paced world of modern web development, mastering JavaScript frameworks is essential. React JS, with its component-based architecture and virtual DOM, has become a front-runner for building dynamic and interactive user interfaces. But where do you begin? While there are countless tutorials, the best way to truly learn is by doing. That’s why we’re diving into a practical project: building a simple React Expense Tracker. This isn’t just a coding exercise; it’s a journey that will equip you with the fundamental skills and understanding needed to tackle more complex React projects. Whether you’re a complete beginner or have some experience, this guide will walk you through each step, explaining concepts in simple terms and providing real-world examples.
Why Build an Expense Tracker?
Expense tracking is a ubiquitous need. From personal budgeting to managing business finances, the ability to monitor where your money goes is crucial. Building a React Expense Tracker provides a tangible and relatable project. It allows you to grasp core React concepts like component structure, state management, event handling, and conditional rendering in a practical and meaningful way. Moreover, it gives you a finished product you can use and expand upon.
What You’ll Learn
By the end of this tutorial, you’ll have a fully functional expense tracker and a solid understanding of:
- Setting up a React project using Create React App.
- Creating and managing React components.
- Handling user input and events.
- Working with state to store and update data.
- Rendering data dynamically.
- Styling components using CSS.
Prerequisites
Before we begin, ensure you have the following:
- A basic understanding of HTML, CSS, and JavaScript.
- Node.js and npm (Node Package Manager) installed on your system.
- A code editor (e.g., VS Code, Sublime Text, Atom).
Step-by-Step Guide: Building the Expense Tracker
1. Setting Up the 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 directory named `expense-tracker` and sets up a basic React application with all the necessary dependencies. Navigate into the project directory using `cd expense-tracker`.
2. Project Structure
Before we start coding, let’s briefly examine the project structure. The `src` directory is where we’ll be spending most of our time. It contains the following key files:
- `App.js`: The main component of our application.
- `index.js`: The entry point of our application.
- `App.css`: Styles for the `App` component.
- `index.css`: Global styles for the application.
3. Creating Components
React is all about components. Let’s create the following components for our expense tracker:
- `ExpenseForm`: A form for adding new expenses.
- `ExpenseList`: A list to display expenses.
- `ExpenseItem`: A single expense item within the list.
- `ExpenseTotal`: Displays the total expenses.
Create a new folder named `components` inside the `src` directory. Inside the `components` folder, create the following files:
- `ExpenseForm.js`
- `ExpenseList.js`
- `ExpenseItem.js`
- `ExpenseTotal.js`
4. Building the ExpenseForm Component
Open `ExpenseForm.js` and add the following code:
import React, { useState } from 'react';
function ExpenseForm({ addExpense }) {
const [description, setDescription] = useState('');
const [amount, setAmount] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
if (description.trim() && amount) {
addExpense({ description, amount: parseFloat(amount) });
setDescription('');
setAmount('');
}
};
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>
<button type="submit">Add Expense</button>
</form>
);
}
export default ExpenseForm;
Explanation:
- We import `useState` to manage the form input values.
- `description` and `amount` are state variables that hold the values entered in the form.
- `handleSubmit` function is called when the form is submitted. It prevents the default form submission behavior, checks for valid input, calls the `addExpense` function (passed as a prop), and clears the form fields.
- The component renders a form with input fields for description and amount, and a submit button.
5. Building the ExpenseList Component
Open `ExpenseList.js` and add the following code:
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:
- We import `ExpenseItem`.
- The `expenses` prop is an array of expense objects.
- The component maps over the `expenses` array and renders an `ExpenseItem` component for each expense. The `key` prop is essential for React to efficiently update the list.
6. Building the ExpenseItem Component
Open `ExpenseItem.js` and add the following code:
import React from 'react';
function ExpenseItem({ expense }) {
return (
<li>
<div>{expense.description}</div>
<div>${expense.amount}</div>
</li>
);
}
export default ExpenseItem;
Explanation:
- This component displays the description and amount of a single expense.
- It receives an `expense` prop, which is an object containing the expense details.
7. Building the ExpenseTotal Component
Open `ExpenseTotal.js` and add the following code:
import React from 'react';
function ExpenseTotal({ expenses }) {
const total = expenses.reduce((acc, expense) => acc + expense.amount, 0);
return (
<div>
<h3>Total Expenses: ${total.toFixed(2)}</h3>
</div>
);
}
export default ExpenseTotal;
Explanation:
- This component calculates and displays the total expenses.
- It receives an `expenses` prop, which is an array of expense objects.
- It uses the `reduce` method to sum the `amount` property of each expense object.
- `toFixed(2)` formats the total to two decimal places.
8. Integrating Components in App.js
Open `App.js` and replace the existing content with the following code:
import React, { useState } from 'react';
import ExpenseForm from './components/ExpenseForm';
import ExpenseList from './components/ExpenseList';
import ExpenseTotal from './components/ExpenseTotal';
function App() {
const [expenses, setExpenses] = useState([]);
const addExpense = (expense) => {
setExpenses([...expenses, { ...expense, id: Date.now() }]);
};
return (
<div>
<h2>Expense Tracker</h2>
<ExpenseForm addExpense={addExpense} />
<ExpenseTotal expenses={expenses} />
<ExpenseList expenses={expenses} />
</div>
);
}
export default App;
Explanation:
- We import the components we created.
- `expenses` is a state variable that holds an array of expense objects.
- `addExpense` function is used to add new expenses to the `expenses` array. It receives an expense object from the `ExpenseForm` and adds a unique `id` to each expense.
- The `App` component renders the `ExpenseForm`, `ExpenseTotal`, and `ExpenseList` components. It passes the `addExpense` function to the `ExpenseForm` and the `expenses` array to the `ExpenseList` and `ExpenseTotal` components as props.
9. Styling the Application (Optional)
To make our expense tracker look better, let’s add some basic styling. Open `src/App.css` and add the following CSS:
.App {
font-family: sans-serif;
max-width: 600px;
margin: 20px auto;
padding: 20px;
border: 1px solid #ccc;
border-radius: 5px;
}
.App h2 {
text-align: center;
}
form {
margin-bottom: 20px;
}
form div {
margin-bottom: 10px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="text"], input[type="number"] {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
button {
background-color: #4CAF50;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #3e8e41;
}
ul {
list-style: none;
padding: 0;
}
li {
display: flex;
justify-content: space-between;
padding: 10px;
border-bottom: 1px solid #eee;
}
You can customize the styles to your liking. Import the CSS file into `App.js` by adding the line `import ‘./App.css’;` at the top of the file.
10. Running the Application
Save all your files. In your terminal, make sure you’re in the `expense-tracker` directory and run the following command:
npm start
This will start the development server, and your expense tracker should open in your browser (usually at `http://localhost:3000`). You can now add expenses, and they will be displayed in the list, and the total will update accordingly.
Common Mistakes and How to Fix Them
1. Not Importing Components Correctly
Mistake: Forgetting to import a component into another component where it is used.
Fix: Use the correct `import` statement at the top of the file. For example, to import `ExpenseItem` into `ExpenseList`, use `import ExpenseItem from ‘./ExpenseItem’;`.
2. Incorrect State Updates
Mistake: Directly modifying the state instead of using the `set…` function provided by `useState`.
Fix: When updating state that is an array or an object, always create a new array or object with the updated values. For example, to add an expense to the `expenses` array, use `setExpenses([…expenses, newExpense])`.
3. Missing the `key` Prop in Lists
Mistake: Not providing a unique `key` prop when rendering a list of items using `.map()`. This can lead to unexpected behavior and performance issues.
Fix: Provide a unique `key` prop to each item in the list. Often, you can use the item’s `id` or a unique identifier. For example: `<ExpenseItem key={expense.id} expense={expense} />`.
4. Typos and Syntax Errors
Mistake: Small errors in the code, such as typos or incorrect syntax, can cause the application to break.
Fix: Carefully review your code for typos and syntax errors. Use your browser’s developer tools (usually accessed by pressing F12) to identify and fix errors. Look at the console tab for error messages.
5. Not Handling Empty Input Fields
Mistake: Allowing the user to submit an expense with empty description or amount fields.
Fix: In the `handleSubmit` function in `ExpenseForm.js`, add a check to ensure that both the description and amount fields have values before adding the expense. Use the `trim()` method to remove leading and trailing whitespace from the description.
Summary / Key Takeaways
Congratulations! You’ve successfully built a simple React Expense Tracker. You’ve learned how to set up a React project, create and organize components, handle user input, manage state, and render data dynamically. This project provides a solid foundation for understanding the core concepts of React. Remember to practice regularly, experiment with different features, and build more complex applications to solidify your skills. The key takeaways are understanding the component-based architecture, the importance of state management, and the use of event handling to make your application interactive. By breaking down the problem into smaller, manageable components, you can build complex user interfaces more efficiently and maintainably. Don’t be afraid to experiment, make mistakes, and learn from them. Every line of code you write brings you closer to becoming a proficient React developer. Keep building, keep learning, and your skills will continue to grow.
Optional FAQ
Q1: How can I add the ability to delete expenses?
A: You can add a delete button to the `ExpenseItem` component. When the button is clicked, you can call a function (passed as a prop from `App.js`) to remove the expense from the `expenses` state array, using the expense’s `id` to identify it.
Q2: How can I add the ability to edit expenses?
A: You can add an edit button to the `ExpenseItem` component. When clicked, it would make the expense’s description and amount editable. You would need to add a new state variable to `App.js` to track the expense being edited and update the expense in the `expenses` array when the edit is saved.
Q3: How do I deploy my React application?
A: There are many ways to deploy a React application. One common way is to use a service like Netlify or Vercel. You’ll typically build your application using `npm run build`, and then deploy the contents of the `build` directory to the hosting service.
Q4: What are some good resources for learning React?
A: The official React documentation ([https://react.dev/](https://react.dev/)) is an excellent resource. You can also find many tutorials on platforms like YouTube, Udemy, and freeCodeCamp.
Q5: How can I improve the styling of my expense tracker?
A: Experiment with different CSS frameworks like Bootstrap, Tailwind CSS, or Material UI to quickly create a more visually appealing interface. You can also customize the CSS in the `App.css` file to match your desired aesthetic.
The journey of a thousand lines of code begins with a single component. As you continue to build and refine your React applications, remember that each project is an opportunity to learn and grow. Embrace the challenges, celebrate your successes, and always keep exploring the vast possibilities of the React ecosystem. Your ability to create dynamic and user-friendly web applications will only improve with each project you undertake.
