Create an Expense Tracker using React-Native
The Expense Tracker application, using React-Native, is an application where users can manage the transactions made and then visualize the expenditure with the help of a pie chart. The users can add transactions while providing the category of expenditure. The application will run on any device and is the scope of a much larger application. The application is cross-platform, which means it can run on any platform.
To give you a better idea of what we’re going to create, let’s watch a demo video.
Demo Video
Playground
Note: This Section is to interact with the app which you are going to build.
Prerequisites and Technologies Used
- Introduction to React Native
- Introduction to React Native Components
- React Native State
- React Native Props
- Expo CLI
- Node.js and npm (Node Package Manager)
Approach
- The application will have a single screen.
- The application will have a pie chart and an add button.
- On pressing the add button, a form will open. The form contains the expense name, amount, and category from a select option.
- Finally, on pressing add, the expense list and chart are updated.
- The expenses are displayed in the form of a scrollable list.
- Each expense tile will also have a delete button to remove it from the list.
- We are using react-native-picker for a dropdown.
- We used react-native-chart-kit.
Step-by-Step Implementation
Step 1: Create a React Native Project
Now, create a project with the following command.
npx create-expo-app app-name --template
Note: Replace the app-name with your app name for example : react-native-demo-app
Next, you might be asked to choose a template. Select one based on your preference as shown in the image below. I am selecting the blank template because it will generate a minimal app that is as clean as an empty canvas in JavaScript.

It completes the project creation and displays a message: "Your Project is ready!" as shown in the image below.

Now go into your project folder, i.e., react-native-demo
cd app-name
Project Structure:

Step 2: Run Application
Start the server by using the following command.
npx expo start
Then, the application will display a QR code.
For the Android users,
- For the Android Emulator, press " a" as mentioned in the image below.
- For the Physical Device, download the " Expo Go " app from the Play Store. Open the app, and you will see a button labeled " Scan QR Code. " Click that button and scan the QR code; it will automatically build the Android app on your device.
For iOS users, simply scan the QR code using the Camera app.
If you're using a web browser, it will provide a local host link that you can use as mentioned in the image below.

Step 3: Update Dependencies
The updated dependencies in the package.json file will look like this.
"dependencies": {
"expo": "53.0.15",
"expo-status-bar": "~2.2.3",
"react": "18.2.0",
"react-native": "0.79.0",
"react-native-chart-kit": "^6.12.0",
"@react-native-picker/picker": "2.11.1"
}
Step 4: Start Coding
Example: We will place the state variables in the App.js and load all the components declared in the respective files here. The code is divided into different files to make it readable.
// App.js
import { StatusBar } from "expo-status-bar";
import { useEffect, useState } from "react";
import { Button, SafeAreaView, Text, View } from "react-native";
import { PieChart } from "react-native-chart-kit";
import styles from "./styles";
import Addform from "./add_expense";
import ExpenseComponent from "./expense_component";
export default function App() {
// Define state variables using the useState hook
const [name, setName] = useState("");
const [amount, setAmount] = useState("");
const [category, setCategory] = useState("Food");
const [expenses, setExpenses] = useState([]);
const categories = ["Food", "Clothes", "Bills", "Others"];
const [addForm, setAddForm] = useState(false);
// Function to open the add expense form
const addExpense = () => {
setAddForm(true);
};
// Initialize the chart data with default values
const [chartData, setChartData] = useState([
{
name: "Food",
amount: 0,
color: "#e62d20",
legendFontColor: "#7F7F7F",
legendFontSize: 15,
},
{
name: "Clothes",
amount: 0,
color: "#27e620",
legendFontColor: "#7F7F7F",
legendFontSize: 15,
},
{
name: "Bills",
amount: 0,
color: "#1c6bd9",
legendFontColor: "#7F7F7F",
legendFontSize: 15,
},
{
name: "Others",
amount: 0,
color: "#5adbac",
legendFontColor: "#7F7F7F",
legendFontSize: 15,
},
]);
// Render the components and UI
return (
<SafeAreaView style={styles.container}>
<StatusBar style="auto" />
<Text style={styles.heading}>Welcome to GeeksforGeeks</Text>
<Text style={styles.heading2}>
Expense Tracker using React-Native
</Text>
{/* Render the PieChart component with data */}
<PieChart
data={chartData}
width={300}
height={200}
chartConfig={{
backgroundGradientFrom: "#1E2923",
backgroundGradientTo: "#08130D",
color: (opacity = 1) => `rgba(26, 255, 146, ${opacity})`,
}}
accessor="amount"
backgroundColor="transparent"
paddingLeft="15"
absolute
/>
{/* Conditional rendering: If addForm is true,
render the Addform component */}
{addForm == true ? (
<Addform
name={name}
setName={setName}
amount={amount}
setAmount={setAmount}
category={category}
setCategory={setCategory}
categories={categories}
setExpenses={setExpenses}
expenses={expenses}
chartData={chartData}
setChartData={setChartData}
setAddForm={setAddForm}
/>
) : (
/* If addForm is false, render the "Add Expense" button */
<View style={styles.row}>
<Button
onPress={addExpense}
color="green"
style={styles.addButton}
title="Add Expense"
/>
</View>
)}
{/* Render the ExpenseComponent */}
<ExpenseComponent
expenses={expenses}
setExpenses={setExpenses}
chartData={chartData}
setChartData={setChartData}
/>
</SafeAreaView>
);
}
// add_expense.js
import { Picker } from "@react-native-picker/picker";
import { Button, Text, TextInput, View } from "react-native";
import styles from "./styles";
// Define the Addform component which is used to add new expenses
export default function Addform({
name,
setName,
amount,
setAmount,
category,
setCategory,
categories,
setExpenses,
expenses,
chartData,
setChartData,
setAddForm,
}) {
return (
<View>
<Text style={styles.heading3}>Add Form</Text>
{/* Input field for expense name */}
<Text style={styles.label}>Expense Name</Text>
<TextInput
onChangeText={(value) => setName(value)}
value={name}
style={styles.textInput}
placeholder="Enter the expense name"
/>
{/* Input field for expense amount */}
<Text style={styles.label}>Amount</Text>
<TextInput
keyboardType="numeric"
onChangeText={(value) => {
// Ensure only numeric values are entered for the amount
value = value.replace(/[^0-9]/g, "");
setAmount(value);
}}
value={amount}
style={styles.textInput}
placeholder="Amount"
/>
{/* Dropdown to select expense category */}
<Text style={styles.label}>Category</Text>
<Picker
style={styles.textInput}
selectedValue={category}
onValueChange={(itemValue, itemIndex) => setCategory(itemValue)}
>
{categories.map((category, index) => {
return (
<Picker.Item
key={index}
label={category}
value={category}
/>
);
})}
</Picker>
{/* Buttons to add or cancel expense */}
<View style={styles.row}>
{/* Add Expense button */}
<Button
onPress={() => {
let amountNumber = parseInt(amount);
if (amountNumber <= 0 || name == "") {
// Validation: Ensure valid amount
// and name are entered
alert("Please enter a valid amount and name");
return;
}
// Add the new expense to the list of expenses
setExpenses([
...expenses,
{
id: new Date().getTime(),
category,
name,
amount: amountNumber,
},
]);
// Update the chart data to reflect the new expense
let newChartData = [...chartData];
let index = newChartData.findIndex(
(item) => item.name == category
);
newChartData[index].amount += amountNumber;
setChartData(newChartData);
// Reset form fields and close the form
setAddForm(false);
setName("");
setAmount("");
setCategory("Food");
}}
title="Add Expense"
/>
{/* Cancel button to close the form
without adding an expense */}
<Button
onPress={() => {
setAddForm(false);
}}
title="Cancel"
/>
</View>
</View>
);
}
// expense_component.js
import { Alert, Button, ScrollView, Text, View } from "react-native";
import styles from "./styles";
export default function ExpenseComponent({
expenses,
setExpenses,
chartData,
setChartData,
}) {
return (
<ScrollView
style={{
marginBottom: 80,
}}
>
{expenses.map((expense) => {
console.log(expense);
return (
<ExpenseListTile
key={expense.id}
expense={expense}
chartData={chartData}
expenses={expenses}
setChartData={setChartData}
setExpenses={setExpenses}
/>
);
})}
</ScrollView>
);
}
const ExpenseListTile = ({
expense,
expenses,
setExpenses,
chartData,
setChartData,
}) => {
return (
<View style={styles.expenseTile}>
<Text style={styles.expenseTileText}>{expense.name}</Text>
<Text style={styles.expenseTileText}>{expense.category}</Text>
<Text style={styles.expenseTileText}>{expense.amount}</Text>
<Button
onPress={() => {
Alert.alert("Delete", "Are you sure you want to delete?", [
{
text: "Yes",
onPress: () => {
let newExpenses = [...expenses];
let index = newExpenses.findIndex(
(item) => item.id == expense.id
);
newExpenses.splice(index, 1);
setExpenses(newExpenses);
let newChartData = [...chartData];
let index2 = newChartData.findIndex(
(item) => item.name == expense.category
);
newChartData[index2].amount -= expense.amount;
setChartData(newChartData);
},
},
{
text: "No",
onPress: () => {
console.log("No");
},
},
]);
}}
title="Delete"
/>
</View>
);
};
// styles.js
import { StyleSheet } from "react-native";
// styles sheet to store all the styles in one place
const styles = StyleSheet.create({
row: {
flexDirection: "row",
justifyContent: "space-evenly",
},
container: {
backgroundColor: "#fff",
height: "100%",
marginTop: 50,
},
heading: {
color: "green",
fontSize: 30,
textAlign: "center",
fontWeight: "bold",
},
addButton: {
padding: 10,
margin: 10,
},
heading2: {
color: "black",
fontSize: 25,
textAlign: "center",
fontWeight: "bold",
},
heading3: {
color: "black",
fontSize: 20,
textAlign: "center",
},
label: {
color: "black",
fontSize: 16,
textAlign: "left",
fontWeight: "bold",
marginLeft: 10,
},
expenseTile: {
// column with 3 cells
flexDirection: "row",
justifyContent: "space-between",
backgroundColor: "lightgrey",
width: "95%",
padding: 10,
margin: 10,
},
expenseTileText: {
fontSize: 20,
width: "22%",
textAlign: "center",
},
formAdd: {
// display: "none",
},
textInput: {
borderRadius: 12,
borderColor: "black",
borderWidth: 1,
padding: 10,
margin: 10,
},
});
export default styles;
Output:
Explanation
- The ExpenseComponent holds each of the expense elements and displays them.
- chartData is used to display the chart, and expenses is used to hold the individual expenses.
- We toggle the form using the addForm boolean variable.
- On pressing the Add Button, it is toggled so that we can show/hide the form.