Building a simple calculator app in React Native is a great beginner-friendly project that helps you understand mobile UI development and JavaScript logic. It allows you to combine interactive components with functional programming to perform real-time calculations.
- Design a user interface with buttons for numbers (0–9), operations (+, −, ×, ÷), and a display screen.
- Implement functions to handle button presses and perform accurate calculations.
- Learn core React Native concepts like components, state management, and event handling.
Here, We start implementing the React Native Calculator App step by step, from setup to task management features.
Step 1: Create a React Native Project
Now, create a project with the following command.
npx create-expo-app app-name --templateNote: 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-nameProject Structure

Step 2: Run Application
Start the server by using the following command.
npx expo startThen, the application will display a QR code.
1. 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.
2. For iOS users, simply scan the QR code using the Camera app.
3. 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: Start Coding
Import libraries: Import required libraries at the top of the file.
// Import React hooks for state and side effects
import {
// Hook for managing component state
useState,
// Hook for performing side effects in function components
useEffect
} from 'react';
import {
// A container that ensures content is rendered within the safe area boundaries of a device
SafeAreaView,
// Component for displaying text
Text,
// A container for grouping other components
View,
// A button-like component that responds to touch events
TouchableOpacity,
// Utility for creating styles for components
StyleSheet,
} from 'react-native';
StyleSheet: Create a StyleSheet to style components like container, resultContainer, inputText, resultText, buttonsContainer, row, button, equalsButton, and buttonText.
// Define styles for the app
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#000',
justifyContent: 'space-between',
},
resultContainer: {
padding: 50,
alignItems: 'flex-end',
},
inputText: {
fontSize: 36,
color: '#AFAFAF',
},
resultText: {
fontSize: 40,
color: '#fff',
marginTop: 10,
},
buttonsContainer: {
padding: 10,
marginBottom: 10,
},
row: {
flexDirection: 'row',
justifyContent: 'space-between',
marginVertical: 6,
},
button: {
backgroundColor: '#1c1c1c',
flex: 1,
alignItems: 'center',
justifyContent: 'center',
margin: 5,
height: 70,
borderRadius: 35,
},
equalsButton: {
backgroundColor: '#1FD660',
flex: 4,
},
buttonText: {
fontSize: 24, // Default font size for button text
color: '#fff', // White text color
},
});
buttons: Define a list of buttons for the calculator.
// Define the layout of calculator buttons
const buttons = [
// First row of buttons
['C', '(', ')', '%'],
// Second row of buttons
['7', '8', '9', '/'],
// Third row of buttons
['4', '5', '6', '*'],
// Fourth row of buttons
['1', '2', '3', '-'],
// Fifth row of buttons
['+/-', '0', '.', '+'],
// Sixth row with only the equals button
['='],
];
buttons UI: Use the code below to show a list of buttons. Organize the buttons with a map function and display the text for each button using a Text component. Make the buttons interactive by wrapping the Text inside a TouchableOpacity. This way, when the user taps on any button, it will call the handlePress function.
{/* Render the calculator buttons */}
<View style={styles.buttonsContainer}>
{buttons.map((row, rowIndex) => (
<View key={rowIndex} style={styles.row}>
{row.map((btn, colIndex) => (
<TouchableOpacity
key={colIndex}
style={[
styles.button,
btn === '=' ? styles.equalsButton : null, // Apply special style for '=' button
]}
onPress={() => handlePress(btn)} // Handle button press
>
<Text style={[styles.buttonText, btn === '=' && { fontSize: 28 }]}>
{btn} {/* Display the button label */}
</Text>
</TouchableOpacity>
))}
</View>
))}
</View>
Input Text & Result Text: Display Input Text (Text user typing) and Result Text ( Answer to user input) using Text component wrapped with View component.
{/* Display the input and result */}
<View style={styles.resultContainer}>
<Text style={styles.inputText}>{input + " "}</Text> {/* Show the current input */}
<Text style={styles.resultText}>{result + " "}</Text> {/* Show the calculated result */}
</View>
handlePress: Function to make every button functional.
const handlePress = (btn) => {
if (btn === 'C') {
// Clear input and result when 'C' is pressed
setInput('');
setResult('');
} else if (btn === '=') {
// Do nothing since the result is calculated automatically
} else if (btn === '+/-') {
// Toggle the sign of the input
if (input.startsWith('-')) setInput(input.substring(1));
else setInput('-' + input);
} else {
// Append the button value to the input
setInput((prev) => prev + btn);
}
};
- useState: Used to manage the state of input and result.
// State to store the current input
const [input, setInput] = useState('');
// State to store the calculated result
const [result, setResult] = useState('');
useEffect: Used to calculate the result whenever the input changes.
// Effect to calculate the result whenever the input changes
useEffect(() => {
try {
if (input) {
// Replace custom operators with JavaScript-compatible ones
let finalInput = input.replace(/×/g, '*').replace(/÷/g, '/');
// Evaluate the expression and update the result
const evalResult = eval(finalInput);
setResult(evalResult.toString());
} else {
// Clear the result if input is empty
setResult('');
}
} catch (e) {
// Handle invalid expressions gracefully
setResult('');
}
}, [input]); // Dependency array ensures this runs when `input` changes
Now, wrap the buttons UI, input Text & result Text components with a SafeAreaView component and return from the App component. Also, ensure to export the App.
Complete Source Code
App.js:
import {
useState, // Hook for managing component state
useEffect // Hook for performing side effects in function components
} from 'react'; // Import React hooks for state and side effects
import {
SafeAreaView, // A container that ensures content is rendered within the safe area boundaries of a device
Text, // Component for displaying text
View, // A container for grouping other components
TouchableOpacity, // A button-like component that responds to touch events
StyleSheet, // Utility for creating styles for components
} from 'react-native'; // Import React Native components for UI
// Define the layout of calculator buttons
const buttons = [
['C', '(', ')', '%'], // First row of buttons
['7', '8', '9', '/'], // Second row of buttons
['4', '5', '6', '*'], // Third row of buttons
['1', '2', '3', '-'], // Fourth row of buttons
['+/-', '0', '.', '+'], // Fifth row of buttons
['='], // Sixth row with only the equals button
];
const App = () => {
// State to store the current input
const [input, setInput] = useState('');
// State to store the calculated result
const [result, setResult] = useState('');
// Effect to calculate the result whenever the input changes
useEffect(() => {
try {
if (input) {
// Replace custom operators with JavaScript-compatible ones
let finalInput = input.replace(/×/g, '*').replace(/÷/g, '/');
// Evaluate the expression and update the result
const evalResult = eval(finalInput);
setResult(evalResult.toString());
} else {
// Clear the result if input is empty
setResult('');
}
} catch (e) {
// Handle invalid expressions gracefully
setResult('');
}
}, [input]); // Dependency array ensures this runs when `input` changes
// Function to handle button presses
const handlePress = (btn) => {
if (btn === 'C') {
// Clear input and result when 'C' is pressed
setInput('');
setResult('');
} else if (btn === '=') {
// Do nothing since the result is calculated automatically
} else if (btn === '+/-') {
// Toggle the sign of the input
if (input.startsWith('-')) setInput(input.substring(1));
else setInput('-' + input);
} else {
// Append the button value to the input
setInput((prev) => prev + btn);
}
};
return (
<SafeAreaView style={styles.container}>
{/* Display the input and result */}
<View style={styles.resultContainer}>
<Text style={styles.inputText}>{input + " "}</Text> {/* Show the current input */}
<Text style={styles.resultText}>{result + " "}</Text> {/* Show the calculated result */}
</View>
{/* Render the calculator buttons */}
<View style={styles.buttonsContainer}>
{buttons.map((row, rowIndex) => (
<View key={rowIndex} style={styles.row}>
{row.map((btn, colIndex) => (
<TouchableOpacity
key={colIndex}
style={[
styles.button,
btn === '=' ? styles.equalsButton : null, // Apply special style for '=' button
]}
onPress={() => handlePress(btn)} // Handle button press
>
<Text style={[styles.buttonText, btn === '=' && { fontSize: 28 }]}>
{btn} {/* Display the button label */}
</Text>
</TouchableOpacity>
))}
</View>
))}
</View>
</SafeAreaView>
);
};
// Define styles for the app
const styles = StyleSheet.create({
container: {
flex: 1, // Take up the full screen
backgroundColor: '#000', // Black background
justifyContent: 'space-between', // Space out elements vertically
},
resultContainer: {
padding: 50, // Add padding around the result area
alignItems: 'flex-end', // Align text to the right
},
inputText: {
fontSize: 36, // Large font for input
color: '#AFAFAF', // Light gray color
},
resultText: {
fontSize: 40, // Larger font for result
color: '#fff', // White color
marginTop: 10, // Add spacing above the result
},
buttonsContainer: {
padding: 10, // Add padding around the buttons
marginBottom: 10, // Add margin at the bottom
},
row: {
flexDirection: 'row', // Arrange buttons in a row
justifyContent: 'space-between', // Space out buttons evenly
marginVertical: 6, // Add vertical spacing between rows
},
button: {
backgroundColor: '#1c1c1c', // Dark gray background for buttons
flex: 1, // Buttons take equal space
alignItems: 'center', // Center button text horizontally
justifyContent: 'center', // Center button text vertically
margin: 5, // Add spacing between buttons
height: 70, // Set button height
borderRadius: 35, // Make buttons circular
},
equalsButton: {
backgroundColor: '#1FD660', // Green background for '=' button
flex: 4, // Make '=' button wider
},
buttonText: {
fontSize: 24, // Default font size for button text
color: '#fff', // White text color
},
});
export default App; // Export the App component as the default export