Building an Expense Tracker with the MERN Stack and React Native

In this blog post, we’ll create a basic Expense Tracker application. Using the MERN stack (MongoDB, Express, React, Node.js) for our backend and React Native for the mobile frontend, you’ll learn how to manage expenses through CRUD operations. This project is ideal for beginners who want to explore full-stack development and mobile app creation.

An Expense Tracker app helps users to monitor their spending by allowing them to add, view, update, and delete expense records. We’ll use the MERN stack—MongoDB, Express and Node.js—for creating backend APIs, and leverage React Native to develop a cross-platform mobile frontend.

Prerequisites

Before you start, ensure you have the following installed at your system:

Node.js & npm: To run your server and manage packages.
MongoDB: Install MongoDb locally from here.
React Native CLI: For setting up your mobile app.

Related read: Building a Native-Like Mobile App with React Native

Setting Up the Backend

1. Initialize Your Node.js Project

Create a new directory for your backend, navigate into it, and initialize your project:

mkdir expense-tracker-backend
cd expense-tracker-backend
npm init -y

2. Install Dependencies

Install the necessary packages: Express for the server, Mongoose for MongoDB integration, and utilities like body-parser and cors:

npm install express mongoose body-parser cors

3. Create the Server

Create a file named server.js and set up your Express server along with the RESTful endpoints for managing expenses:

// server.js
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cors = require('cors');

const app = express();
app.use(cors());
app.use(bodyParser.json());


// Connect to MongoDB
mongoose.connect('mongodb://localhost/expenseTracker');
mongoose.connection.once('open', () => {
console.log('Connected to MongoDB');
});

// Define an Expense model
const ExpenseSchema = new mongoose.Schema({
description: String,
amount: Number,
category: String,
date: { type: Date, default: Date.now },
});
const Expense = mongoose.model('Expense', ExpenseSchema);

// REST API Endpoints
// Get all expenses
app.get('/expenses', async (req, res) => {
const expenses = await Expense.find();
res.json(expenses);
});

// Add a new expense
app.post('/expenses', async (req, res) => {
const { description, amount, category } = req.body;
const newExpense = new Expense({ description, amount, category });
const savedExpense = await newExpense.save();
res.json(savedExpense);
});

// Update an expense
app.put('/expenses/:id', async (req, res) => {
const updatedExpense = await Expense.findByIdAndUpdate(req.params.id, req.body, {
new: true,
});
res.json(updatedExpense);
});

// Delete an expense
app.delete('/expenses/:id', async (req, res) => {
await Expense.findByIdAndDelete(req.params.id);
res.json({ message: 'Expense deleted' });
});


// Start the server
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});

Run your server with:

node server.js

You should see a message confirming the connection to MongoDB and the server running on the specified port.

Ready to Build Your Next App with MERN and React Native?

Setting Up the React Native App

1. Initialize Your Mobile App

Open a new terminal and create a new project using following command:

npx react-native init expense-tracker-mobile
cd expense-tracker-mobile
npm start

2. Install Axios for API Requests

Inside your mobile project, install Axios to interact with the backend API:

npm install axios

3. Create the Expense Tracker Component

Edit your main app file (App.js) to build a simple UI that displays expenses, and allows you to add, update, or delete them. Here’s a basic example:

// App.js
import React, { useEffect, useState } from 'react';
import { StyleSheet, View, TextInput, Button, FlatList, Text, TouchableOpacity } from 'react-native';
import axios from 'axios';

const API_URL = 'http://your-ip-address:5000/expenses'; // Replace 'your-ip-address' with your machine's IP if testing on a device

export default function App() {
const [expenses, setExpenses] = useState([]);
const [description, setDescription] = useState('');
const [amount, setAmount] = useState('');
const [category, setCategory] = useState('');

// Fetch expenses from the backend
const fetchMyExpenses = async () => {
try {
const response = await axios.get(API_URL);
setExpenses(response.data);
} catch (error) {
console.error('Error fetching expenses:', error);
}
};

useEffect(() => {
fetchMyExpenses();
}, []);

// Add a new expense
const addMyExpense = async () => {
if (!description || !amount) return;
try {
await axios.post(API_URL, {
description,
amount: parseFloat(amount),
category,
});
setDescription('');
setAmount('');
setCategory('');
fetchMyExpenses();
} catch (error) {
console.error('Error adding expense:', error);
}
};

// Delete an expense
const deleteExpense = async (id) => {
try {
await axios.delete(`${API_URL}/${id}`);
fetchMyExpenses();
} catch (error) {
console.error('Error deleting expense:', error);
}
};

return (
<View style={styles.container}>
<Text style={styles.header}>Expense Tracker</Text>
<View style={styles.inputContainer}>
<TextInput
style={styles.input}
placeholder="Description"
value={description}
onChangeText={setDescription}
/>
<TextInput
style={styles.input}
placeholder="Amount"
value={amount}
onChangeText={setAmount}
keyboardType="numeric"
/>
<TextInput
style={styles.input}
placeholder="Category (Optional)"
value={category}
onChangeText={setCategory}
/>
<Button title="Add Expense" onPress={addMyExpense} />
</View>
<FlatList
data={expenses}
keyExtractor={(item) => item._id}
renderItem={({ item }) => (
<View style={styles.expenseItem}>
<Text style={styles.expenseText}>
{item.description} - ${item.amount} {item.category ? `(${item.category})` : ''}
</Text>
<Button title="Delete" onPress={() => deleteExpense(item._id)} />
</View>
)}
/>
</View>
);
}
coma

Conclusion

In this blog, we built a simple Expense Tracker application using the MERN stack for the backend and React Native for the mobile frontend. This blog covers basic concepts like REST API creation, MongoDB data handling, and integrating a mobile app with a backend service—all without the complexity of authentication. In the next blog we will learn how we can authenticate our Rest APIs so that no unauthorized user can use these api’s.

Happy coding, and enjoy exploring full-stack mobile development with the MERN and React Native!

Keep Reading

Keep Reading

  • Service
  • Career
  • Let's create something together!

  • We’re looking for the best. Are you in?