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
I kind of got it, the version of chooseOperation mentioned below seems to do the thing
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?
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 lineif (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
andcurrent
properties when appropriate.