DEV Community

loading...

Simple Calculator App in React

Akshay R
Front End Developer
Updated on ・4 min read

Simple Calculator is the best way to build a good understanding of react concepts. Let me know if there is any best way in which the same code can be implemented
So please do comment on what you think.

Following are the links to source code:
GitHub: https://github.com/akshayrak/react-simpl-calculator1234.git
StackBlitz: https://stackblitz.com/edit/react-simpl-calculator1234?file=src/App.js

Application link: https://react-simpl-calculator1234.stackblitz.io

I have started it by creating a simple form

<form>
        <input
          type="text"
          onChange={e => setInput(e.target.value)}
          value={input} 
         />
</form>
Enter fullscreen mode Exit fullscreen mode

we can use useState hook to maintain the state of the form

const [input, setInput] = useState("0")
Enter fullscreen mode Exit fullscreen mode

Default value will be zero

For the buttons we can create a variable and put all the symbols in an array

 const symbols = [
    'c',
    '<-',
    '%',
    '/',
    '7',
    '8',
    '9',
    'X',
    '4',
    '5',
    '6',
    '-',
    '1',
    '2',
    '3',
    '+',
    '.',
    '0',
    '='
  ];
Enter fullscreen mode Exit fullscreen mode

so now we can use 'map' method in js to loop through all the elements and return a array of button elements

<div>
        {symbols.map((symbol, i) => (
          <button key={i} onClick={()=>handleSymbol(symbol)}>
            {symbol}
          </button>
        ))}
</div>
Enter fullscreen mode Exit fullscreen mode

At this point it should look somewhat like this
image of the simple calculator application till now

This is all the UI we want, now we can implement the logic for calculations.

whenever a button is clicked "handleSymbol" method is triggered and the respective "symbol" is passed as an argument. Now we need to check what that symbol is and what should we do with it.

So here I am using "input" state for maintaining the state of the form and also displaying the result in the same TextField. so we just need to set the final answer to "input".

Now to get the answer we need to do few checks,
check1: whether to Concatenate or to backspace or to delete or to calculate
This can be done simply using if else statements

if (symbol != 'c' && symbol != '<-' && symbol != '=') {
//concatenate
}else if(symbol == 'c') {
//delete
} else if (symbol == '<-' && input != '0'&&input!='') {
//backspace
} else if (symbol == '=') {
//calculate
}
Enter fullscreen mode Exit fullscreen mode

if it is Concatenate than we need to check what it is

if (symbol == '.') {
        let temp = input.match(/[\d\.]+|\D+/g);//separate the string and the integer
        temp==null?temp=["0"]:null  //sets 0 if temp is null

         //checks whether dot exists or not in the last element (we can't have two dots in the same number)
        if (!temp[temp.length - 1].includes('.')) {
        //checks whether dot is typed after a symbol
          if (temp[temp.length - 1] == '+' ||
          temp[temp.length - 1] == '-' ||
          temp[temp.length - 1] == 'X' ||
          temp[temp.length - 1] == '/' ||
          temp[temp.length - 1] == '%') {
            //if it is typed after a symbol than it adds '0.' (so that it looks like a number)
            setInput(prev => prev + '0.')
        }
          else {
            setInput(prev => prev + symbol)
          }
        }
      }
Enter fullscreen mode Exit fullscreen mode

if its not a don't and if its some thing else than

else{
 let temp = input.match(/[^\d]+|\d+/g);//separate the string and the integer
        temp==null?temp=["0"]:null //sets 0 if temp is null

        //these two if blocks checks whether the previously typed and current typed are operators (you can't put two operators next to each other)
        if (
          temp[temp.length - 1] == '+' ||
          temp[temp.length - 1] == '-' ||
          temp[temp.length - 1] == 'X' ||
          temp[temp.length - 1] == '/' ||
          temp[temp.length - 1] == '%'
        ) {
          //checks whether its a symbol or number
          if (
            symbol == '+' ||
            symbol == '-' ||
            symbol == 'X' ||
            symbol == '/' ||
            symbol == '%'
          ) {
            //if symbol than remove the previous one and concatenate the new one
            setInput(prev => prev.slice(0, -1));
            setInput(prev => prev + symbol);
          } else {
           //if number than concatenate
            setInput(prev => prev + symbol);
          }
        } else {
         //if previous one is a number than concatenate the current one too
          setInput(prev => prev + symbol);
        }
      }
Enter fullscreen mode Exit fullscreen mode

now if its a backspace or a delete than its simple

 else if (symbol == 'c') {
      setInput('0');
    } else if (symbol == '<-' && input != '0'&&input!='') {
      setInput(prev => prev.slice(0, -1));
    }
Enter fullscreen mode Exit fullscreen mode

if its an equals symbol than we need to calculate

else if (symbol == '=') {
     let temp = input.match(/[^\d]+|\d+/g);//separate the string and the integer
        temp==null?temp=["0"]:null //sets 0 if temp is null

//checks if the late typed character is a operator
      if (
        temp[temp.length - 1] == '+' ||
        temp[temp.length - 1] == '-' ||
        temp[temp.length - 1] == '/' ||
        temp[temp.length - 1] == 'X'
      ) {
//if its a operator than remove
        temp.pop();
      }

//Now we are using simple BODMAS rule to calculate


//if % exists than divide the number by 100 and multiply with the following number
      while (temp.includes('%')) {
        const index = temp.indexOf('%');
        const num1 = parseFloat(temp[index - 1]);
        let tempResult = (num1 / 100).toFixed(2).toString();
        temp.splice(index, 1, 'X');
        temp.splice(index - 1, 1, tempResult);
      }

//if '/' exists than divide the two numbers and remove them and replace the result
      while (temp.includes('/')) {
        const index = temp.indexOf('/');
        const num1 = parseFloat(temp[index - 1]);
        const num2 = parseFloat(temp[index + 1]);
        const tempResult = (num1 / num2).toFixed(2).toString();
        temp.splice(index, 1);
        temp.splice(index, 1);
        temp.splice(index - 1, 1, tempResult);
      }

//if 'X' exists than multiply the two numbers and remove them and replace the result
      while (temp.includes('X')) {
        const index = temp.indexOf('X');
        const num1 = parseFloat(temp[index - 1]);
        const num2 = parseFloat(temp[index + 1]);
        let tempResult = (num1 * num2).toFixed(2).toString();
        temp.splice(index, 1);
        temp.splice(index, 1);
        temp.splice(index - 1, 1, tempResult);
      }


//if '+' exists than add the two numbers and remove them and replace the result
      while (temp.includes('+')) {
        const index = temp.indexOf('+');
        const num1 = parseFloat(temp[index - 1]);
        const num2 = parseFloat(temp[index + 1]);
        let tempResult = (num1 + num2).toFixed(2).toString();
        temp.splice(index, 1);
        temp.splice(index, 1);
        temp.splice(index - 1, 1, tempResult);
      }

//if '-' exists than subtract the two numbers and remove them and replace the result
      while (temp.includes('-')) {
        const index = temp.indexOf('-');
        const num1 = parseFloat(temp[index - 1]);
        const num2 = parseFloat(temp[index + 1]);
        let tempResult = (num1 - num2).toFixed(2).toString();
        temp.splice(index, 1);
        temp.splice(index, 1);
        temp.splice(index - 1, 1, tempResult);
      }

//result can be set to input so that we can show it in the same textBox in which we type
      setInput(temp[0]);
    }
Enter fullscreen mode Exit fullscreen mode

I have included most of the explanation as comments, so in case if you don't understand let me know.

And if you can make it better let me know as well.

Thanks
Akshay

Discussion (0)