skip to Main Content

I am working on a simple calculator app using React JS. Most of the things are working as expected. However I want the operator parameter to mutate when two or more buttons containing the operation symbols e.g., "*" , "+" are clicked consecutively.

Below is the relevant portion of code for reference

class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      previous: "",
      current: "",
      operation: "",
    };
  }

  clear = () => {
    this.setState(() => ({
      previous: "",
      current: "0",
      operation: null,
    }));
  };

  delete = () => {
    this.setState(() => ({
      current: this.state.current.slice(0, -1),
    }));
  };

  appendNumber = (number) => {
    const { current } = this.state;
    { current === "0" && this.delete() }
    if (number === "." && current.includes(".")) return;
    this.setState((prevState) => ({
      current: prevState.current + number,
    }));
  };

  chooseOperation = (op) => {
    const { previous, current, operation } = this.state;
    if (current === "") return;
    if (previous !== "") {
      this.compute();
    }

    this.setState((prevState) => ({
      operation: op,
      previous: prevState.current,
      current: "",
    }));
  };

  compute = () => {
    let computation;
    const { previous, current, operation } = this.state;
    const prev = parseFloat(previous);
    const curr = parseFloat(current);
    if (isNaN(previous) || isNaN(current) || !operation) return;

    switch (operation) {
      case "+":
        computation = prev + curr;
        break;
      case "-":
        computation = prev - curr;
        break;
      case "*":
        computation = prev * curr;
        break;
      case "÷":
        computation = prev / curr;
        break;
      default:
        return;
    }

    this.setState({
      current: computation,
      operation: "",
      previous: "",
    });

    if (operation != null) {
      this.setState({
        previous: `${previous} ${operation} ${current}`,
      });
    }
   }

These are the few things that I tried:
Within the chooseOperation method I tried to implement the said functionality using a conditional to update the operator parameter

 if (["÷", "*", "+", "-"].some((value) => operation.includes(value))) {
      this.setState((prevState) => ({
        operation: prevState.operation.replace(/[+-*/]/g, op),
      }));
    } else {
      this.setState({
        operation: op,
      });
    }

I also tried this

const lastChar = operation.charAt(operation.length - 1);
    if (["÷", "*", "+", "-"].includes(lastChar)) {
      this.setState({
        operation: operation.slice(0, -1) + op,
      });
    } else {
      this.setState((prevState) => ({
        operation: `${prevState.operation} ${op}`,
        previous: prevState.current,
        current: "",
      }));
    }

I tried to address the issue by writing a conditional within the compute method just before the switch statement

if (["÷", "*", "+", "-"].some((value) => operation.includes(value))) {
      this.setState((prevState) => ({
        operation: prevState.operation.slice(0, -1),
      }));
    }

However none of the things have worked so far. Neither I’ve tried nor I want to add any extra parameter since most of the other functionalities work quiet expectedly.

2

Answers


  1. Chosen as BEST ANSWER

    I kind of got it, the version of chooseOperation mentioned below seems to do the thing

    chooseOperation = (op) => {
      const {
        previous,
        current,
        operation
      } = this.state;
      // if (current === "") return;
      if (previous !== "" && current !== "") {
        this.compute();
      }
    
      this.setState(
        (prevState) => ({
          operation: op,
          previous: prevState.current === "" ? prevState.previous : prevState.current,
          current: "",
        })
      );
    }

    I modified the conditional containing this.compute(). However there is more scope for improvement, for example the delete method is throwing error when applied on the output obtained after the execution of this.compute(). Any idea how to fix that?


  2. When the user types in a number (6) followed by an operator (+), all is good. In state we now have {previous: 6, operation: "+", current: ""}. But when the user presses another operator the line if (current === "") return; kicks in and no update happens.

    To fix, we will always allow the operator to be updated, your condition to run compute makes sense where it is, and then update the previous and current properties when appropriate.

    chooseOperation = (op) => {
      const { previous, current, operation } = this.state;
    
      if (previous !== "") {
        this.compute();
      }
    
      this.setState((prevState) => ({
        operation: op,
        previous: prevState.current === "" ? prevState.previous : prevState.current,
        current: prevState.previous === "" ? prevState.current : ""
      }));
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search