I need an eval alternative for my calculator app

Viewed 26

I'm using eval in my calculate function. I want to use an alternative, but searching online is leading me to very complex solutions or ones that require me to completely rewrite my code. Is there any way to use something else in the calculate function without having to drastically change the rest of my code?

This is my App.js code

import Buttons from "./components/Buttons";
import Display from "./components/Display";
import {useState} from "react";
import Screen from "./components/Screen";


function App() {

  const [disp, setDisp] = useState("")

  const [value, setValue] = useState("")

  function handleChange(event) {
    const input = event.target.value

    setValue(prevState => prevState + input)
    setDisp(input)
  }

  function errorCatch() {
    setValue(prevState => 
    prevState === "+" ||
    prevState === "*" ||
    prevState === "/" ||
    prevState === "-+" ||
    prevState === "-*" ||
    prevState === "-/" ||
    prevState === "--"
    ? setDisp("ERROR")
    : prevState.length > 20
    ? setDisp("MAX LIMIT REACHED")
    : prevState)
  }

  function calculate() {

    setDisp(eval(value))
    setValue(value)
 
  }

  function backspace() {
    setValue(value.slice(0, -1))
    setDisp(disp.slice(0, -1))
  }

  function clear() {
    setValue("")
    setDisp("")
  }

  return (
    <div className="App">
      <div className="calculator">
      <Screen value={value}/>
      <Display disp={disp}/>
      <Buttons handleChange={handleChange} calculate={calculate} backspace={backspace} clear={clear} errorCatch={errorCatch}/>
      </div>

    </div>
  );
}

export default App;

This is my Buttons.js code


const btnValues = [
    ["AC", "DEL", "/"],
    [7, 8, 9,"*"],
    [4, 5, 6, "-"],
    [1, 2, 3, "+"],
    [0, ".", "="]
]


export default function Buttons(props) {  
    return (
        <div className="buttons">
            {
                btnValues.flat().map((i) => {
                    return (
                        <button 
                            key={i}
                            value={i}
                            onClick={(e) =>
                                i === "AC"
                                ? props.clear(e)
                                : i === "="
                                ? props.calculate(e)
                                : i === "DEL"
                                ? props.backspace(e)
                                : props.handleChange(e) || props.errorCatch(e)
                            }
                            className={
                                i === "AC" ? "AC" :
                                i === "=" ? "equal" :
                                i === "/" || i === "*" || i === "+" || i === "-" ? "light" :
                                ""
                            }
                        >{i}</button>
                    )
                })
            }
        </div>
    )
}
1 Answers

Seems like you're trying to build something very similar to this article.

Search this article for a section on compute function - you'll find there a simple parser that parses the input and calculates the output without using eval.

I'm coping the relevant function here for your convenience:

compute() {
    let computation
    const prev = parseFloat(this.previousOperand)
    const current = parseFloat(this.currentOperand)
    if (isNaN(prev) || isNaN(current)) return
    switch (this.operation) {
      case '+':
        computation = prev + current
        break
      case '-':
        computation = prev - current
        break
      case '*':
        computation = prev * current
        break
      case '÷':
        computation = prev / current
        break
      default:
        return
    }
    this.currentOperand = computation
    this.operation = undefined
    this.previousOperand = ''
  }
Related