Open In App

Build a Calculator using React Native

Last Updated : 18 May, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Building a simple calculator app in React Native is an exciting project. You'll create an interface with buttons for numbers (0-9) and operations (+, -, ×, ÷), along with a display area for showing input and results. Using React Native, you'll write functions that handle button presses and perform calculations. This project combines UI design with JavaScript logic, making it a great way to learn.

Build-a-Calculator-using-React-Native


To give you a better idea of what we’re going to create, let’s watch a demo video.

Demo Video


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: Start Coding

- Import libraries: Import required libraries at the top of the file.

JavaScript
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


- StyleSheet: Create a StyleSheet to style components like container, resultContainer, inputText, resultText, buttonsContainer, row, button, equalsButton, and buttonText.

JavaScript
// 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
  },
});


- buttons: Define a list of buttons for the calculator.

JavaScript
// 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
];


- 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.

JavaScript
{/* 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.

JavaScript
{/* 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.

JavaScript
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.

JavaScript
// 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.

JavaScript
// 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:

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

Output:



Next Article

Similar Reads