the-geeky-codes-high-resolution-logo-color-on-transparent-background geeky code red logo
  • Home
  • AI
    AIShow More
    generate vector icons
    Generate Vector Icons with ChatGPT DALLE 3: A Comprehensive Guide
    14 Min Read
    Dalle 3
    Dalle 3: A Step-by-Step Guide to Mastering AI Art Generation
    4 Min Read
    5 Best AI Tools to Convert Images to Video Animations
    5 Best AI Tools to Convert Images to Video Animations
    8 Min Read
    Exploring the Impressive Mistral 7B Model
    Exploring the Impressive Mistral 7B Model for Text Summarization and Coding
    6 Min Read
    The AI Revolution this week
    Must Read – The AI Revolution this week 30 Sep 2023: Integrating AI Tools into Everyday Life
    6 Min Read
  • Tutorial
    • React js
    • Python
    • Javascript
  • AI Tools
Reading: Build a Simple Calculator App with React, Tailwind CSS. Displays History
Share
the geeky codesthe geeky codes
Aa
  • AI
  • AI Tools
  • Javascript
  • Python
  • React js
  • Advertise
Search
  • Categories
    • AI
    • AI Tools
    • Javascript
    • Python
    • React js
  • More
    • Advertise
Follow US
Copyright ©2023 The Geeky codes. All Rights Reserved.
the geeky codes > Blog > Tutorial > React js > Build a Simple Calculator App with React, Tailwind CSS. Displays History
TutorialReact js

Build a Simple Calculator App with React, Tailwind CSS. Displays History

thegeekycodes By thegeekycodes 6 October 2023 8 Min Read
Build a Simple Calculator App with React
SHARE

Intro – Build a Simple Calculator App with React, Tailwind CSS

In this tutorial, we’ll be using React, a popular JavaScript library, along with Tailwind CSS for styling, to create a simple calculator that also displays a history of calculations.

Contents
Intro – Build a Simple Calculator App with React, Tailwind CSSGetting StartedSetting up the ProjectDesigning the Calculator ComponentBuilding the LogicHandling User InteractionRendering the UIComplete Code💁 Check out our other articles😃

Getting Started

Before diving in, make sure you have the following prerequisites installed:

  • Node.js and npm
  • A code editor like Visual Studio Code
  • Basic understanding of React and JavaScript

Setting up the Project

First, let’s create a new React project using Create React App, and install Tailwind CSS.

npx create-react-app simple-calculator
cd simple-calculator
npx tailwindcss init -p

Designing the Calculator Component

Create a new file SimpleCalculator.tsx in the src directory. Now let’s start by importing the necessary dependencies and setting up our main calculator component.

import { useState } from "react";

interface CacheItem {
    expression: string;
    result: string;
}

const calculatorValues = [
    "7", "8", "9", "4", "5", "6", "1", "2", "3", "0", "+", "-", "*", "/"
];

function SimpleCalculator() {
    const [input, setInput] = useState<string>("");
    const [cache, setCache] = useState<CacheItem[]>([]);
}

Building the Logic

Our calculator will have basic arithmetic operations. The evaluateExpression function will parse and evaluate the expression in the input. For simplicity, we’ll use the eval function, but keep in mind, it’s not recommended for production due to security concerns.

function evaluateExpression() {
    // Get the last character of the input after trimming any whitespace
    const lastChar = input.trim().slice(-1);
    // Define the operators that are allowed in the expression
    const operators = ["+", "-", "*", "/"];

    // Check if the expression ends with an operator
    if (operators.includes(lastChar)) {
        // If so, log an error to the console and exit the function early
        console.error("Expression ends with an operator, cannot evaluate.");
        return;
    }

    try {
        // Attempt to evaluate the expression
        // Note: It's recommended to avoid the use of eval due to security risks,
        // and consider using a safer evaluation method instead
        // The eslint-disable-next-line no-eval comment disables the eslint warning about using eval
        // eslint-disable-next-line no-eval
        const result = eval(input.replace(/\s/g, ""));  // Remove any whitespace from the input before evaluating

        // Update the cache state with the new expression and result
        setCache((prevCache) => [
            ...prevCache,
            { expression: input, result },
        ]);

        // Update the input state with the result, converted to a string
        setInput(result.toString());
    } catch (e) {
        // If an error occurs while evaluating, log the error to the console
        console.error("Error evaluating expression:", e);
    }
}

Handling User Interaction

We’ll set up a function onButtonClick to handle button clicks, updating the input based on the button clicked.

   function onButtonClick(value) {
    // Define the operators that are allowed in the expression
    const operators = ["+", "-", "*", "/"];
    // Get the last character of the current input
    const lastChar = input[input.length - 1];

    // Check if the clicked button is an operator
    if (operators.includes(value)) {
        // If so, check if the last character of the current input is also an operator
        if (operators.includes(lastChar)) {
            // If the last character is an operator, replace it with the new operator
            setInput(input.slice(0, -1) + value);
        } else {
            // If the last character is not an operator, append the new operator to the input
            setInput(input + value);
        }
    } else {
        // If the clicked button is not an operator, append the value to the input
        setInput(input + value);
    }
}

Rendering the UI

Now, let’s lay out our calculator and history component using Tailwind CSS for styling.

return (
        <div className="min-h-screen flex items-center justify-center bg-gradient-to-r from-blue-400 via-blue-500 to-purple-500">
            <div className="flex flex-col md:flex-row gap-2">
                <div className="p-8 bg-white rounded-lg shadow-2xl mr-4">
                    <input
                        type="text"
                        readOnly
                        value={input}
                        className="w-full p-4 text-2xl border border-gray-300 rounded-lg mb-4 shadow-inner"
                    />
                    <div className="grid grid-cols-4 gap-4">
                        {calculatorValues.map((item, index) => (
                            <button
                                key={index}
                                onClick={() => onButtonClick(item)}
                                className="py-2 px-4 text-xl bg-blue-500 text-white rounded-full transition duration-300 ease-in-out transform hover:bg-blue-600 active:scale-95"
                            >
                                {item}
                            </button>
                        ))}
                        <button
                            onClick={evaluateExpression}
                            className="col-span-2 py-2 px-4 text-xl bg-green-500 text-white rounded-full transition duration-300 ease-in-out transform hover:bg-green-600 active:scale-95"
                        >
                            =
                        </button>
                        <button
                            onClick={() => setInput("")}
                            className="col-span-2 py-2 px-4 text-xl bg-red-500 text-white rounded-full transition duration-300 ease-in-out transform hover:bg-red-600 active:scale-95"
                        >
                            Clear
                        </button>
                    </div>
                </div>
                <div className="p-8 bg-white rounded-lg shadow-2xl">
                    <h2 className="mb-4 text-xl font-bold">History</h2>
                    <ul>
                        {cache.map((item, index) => (
                            <li key={index} className="mb-2">
                                {item.expression} = {item.result}
                            </li>
                        ))}
                    </ul>
                </div>
            </div>
        </div>
    );

Import the SimpleCalculator component into your App.tsx file, you would use an import statement at the top of the file. Here is how you would do it:

import React from 'react';
import SimpleCalculator from './SimpleCalculator';  // Assuming SimpleCalculator.js is in the same directory as App.tsx

function App() {
  return (
    <div className="App">
      <SimpleCalculator />
    </div>
  );
}

export default App;

Complete Code

import { useState } from "react";
interface CacheItem {
    expression: string;
    result: string;
}
const calculatorValues = [
    "7",
    "8",
    "9",
    "4",
    "5",
    "6",
    "1",
    "2",
    "3",
    "0",
    "+",
    "-",
    "*",
    "/",
];
function SimpleCalculator() {
    const [input, setInput] = useState<string>("");
    const [cache, setCache] = useState<CacheItem[]>([]);

    function evaluateExpression() {
        const lastChar = input.trim().slice(-1);
        const operators = ["+", "-", "*", "/"];

        if (operators.includes(lastChar)) {
            console.error("Expression ends with an operator, cannot evaluate.");
            return;
        }

        try {
            // eslint-disable-next-line no-eval
            const result = eval(input.replace(/\s/g, ""));
            setCache((prevCache) => [
                ...prevCache,
                { expression: input, result },
            ]);
            setInput(result.toString());
        } catch (e) {
            console.error("Error evaluating expression:", e);
        }
    }

    function onButtonClick(value) {
        const operators = ["+", "-", "*", "/"];
        const lastChar = input[input.length - 1];

        if (operators.includes(value)) {
            if (operators.includes(lastChar)) {
                setInput(input.slice(0, -1) + value); // Replace the last operator with the new operator
            } else {
                setInput(input + value);
            }
        } else {
            setInput(input + value); // SimpleCalculatorend the digit or operator to the input
        }
    }

    return (
        <div className="min-h-screen flex items-center justify-center bg-gradient-to-r from-blue-400 via-blue-500 to-purple-500">
            <div className="flex flex-col md:flex-row gap-2">
                <div className="p-8 bg-white rounded-lg shadow-2xl mr-4">
                    <input
                        type="text"
                        readOnly
                        value={input}
                        className="w-full p-4 text-2xl border border-gray-300 rounded-lg mb-4 shadow-inner"
                    />
                    <div className="grid grid-cols-4 gap-4">
                        {calculatorValues.map((item, index) => (
                            <button
                                key={index}
                                onClick={() => onButtonClick(item)}
                                className="py-2 px-4 text-xl bg-blue-500 text-white rounded-full transition duration-300 ease-in-out transform hover:bg-blue-600 active:scale-95"
                            >
                                {item}
                            </button>
                        ))}
                        <button
                            onClick={evaluateExpression}
                            className="col-span-2 py-2 px-4 text-xl bg-green-500 text-white rounded-full transition duration-300 ease-in-out transform hover:bg-green-600 active:scale-95"
                        >
                            =
                        </button>
                        <button
                            onClick={() => setInput("")}
                            className="col-span-2 py-2 px-4 text-xl bg-red-500 text-white rounded-full transition duration-300 ease-in-out transform hover:bg-red-600 active:scale-95"
                        >
                            Clear
                        </button>
                    </div>
                </div>
                <div className="p-8 bg-white rounded-lg shadow-2xl">
                    <h2 className="mb-4 text-xl font-bold">History</h2>
                    <ul>
                        {cache.map((item, index) => (
                            <li key={index} className="mb-2">
                                {item.expression} = {item.result}
                            </li>
                        ))}
                    </ul>
                </div>
            </div>
        </div>
    );
}

export default SimpleCalculator;

💁 Check out our other articles😃

 👉  Generate a free Developer Portfolio website with AI prompts

 👉  Creating a Toggle Switcher with Happy and Sad Faces using HTML, CSS, and JavaScript

TAGGED: Calculator, Coding Tutorial, front-end development, History Feature, javascript, react, Tailwind CSS, UI/UX Design, Web Development

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Twitter Copy Link Print
Previous Article Stockimg AI Stockimg AI: AI Image Generation for Teams
Next Article Phrasly AI Phrasly AI: Transforms AI-generated content into undetectable text
Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Twitter Follow
Telegram Follow

Subscribe Now

Subscribe to our newsletter to get our newest articles instantly!

Most Popular
Advanced Routing Techniques in Nextjs 15
Advanced Routing Techniques in Next js 15
20 November 2024
Attachment Details Image-to-Text-Converter-with-Claude-Nextjs-15
Building an AI-Powered Image-to-Text Converter with Claude, Next.js 15, and Vercel AI SDK
20 November 2024
Generate-Dynamic-OpenGraph-Images-in-Nextjs15
How to Generate Dynamic OpenGraph Images in Next.js App Router 15 with TypeScript
20 November 2024
Google Analytics 4 in Nextjs 14
How to Install Google Analytics 4 in Next.js 15 (App Router) with TypeScript [2024]
20 November 2024
docker compose
Getting Started with Docker Compose
20 November 2024

You Might Also Like

Advanced Routing Techniques in Nextjs 15
TutorialNextjs

Advanced Routing Techniques in Next js 15

7 Min Read
Attachment Details Image-to-Text-Converter-with-Claude-Nextjs-15
TutorialNextjs

Building an AI-Powered Image-to-Text Converter with Claude, Next.js 15, and Vercel AI SDK

4 Min Read
Generate-Dynamic-OpenGraph-Images-in-Nextjs15
TutorialNextjs

How to Generate Dynamic OpenGraph Images in Next.js App Router 15 with TypeScript

9 Min Read
Google Analytics 4 in Nextjs 14
TutorialNextjs

How to Install Google Analytics 4 in Next.js 15 (App Router) with TypeScript [2024]

6 Min Read

Always Stay Up to Date

Subscribe to our newsletter to get our newest articles instantly!

the geeky codes geeky code red logo

Providing valuable resources for developers in the form of code snippets, software tutorials, and AI related content.

About

  • About Us
  • Contact
  • Terms and Conditions
  • Privacy Policy
  • Disclaimer
  • Affiliate Disclosure

Resource

  • The Art of AI Prompt Engineering: Crafting Effective Inputs for AI Models

Get the Top 10 in Search!

Looking for a trustworthy service to optimize the company website?
Request a Quote
© 2023 The Geeky Codes. All Rights Reserved
We are happy to see you join Us!

🔥📢Subscribe to our newsletter and never miss our latest code snippets, tutorials and AI updates

Zero spam, Unsubscribe at any time.
Welcome Back!

Sign in to your account

Lost your password?