Reputation: 273
I´m trying to make a React calculator. It´s mostly done, but I have one problem I don´t know how to correct: I don´t want to let users enter expressions starting with more than one "0" AND expressions such as "01" should be replaced to just "1". I thought about using string methods to limit that, but it´s not budging. EDIT: I know why my solution doesn´t work (input will never have more than one zero), but I don´t know any other way to fix it.
class Calculator extends Component {
constructor(props) {
super(props);
this.state = { value: "" };
this.handleClick = this.handleClick.bind(this);
}
handleClick(evt) {
const id = evt.target.id;
const result = evt.target.value;
if (id === "clear") {
this.setState({ value: 0 });
} else if (id === "equals") {
this.setState({ value: math.eval(this.state.value) });
} else {
result.toString().includes("00");
this.setState({ value: this.state.value + result.replace("00", "0") });
console.log(this.state.value);
}
}
render() {
return (
<div id="container">
<Display value={this.state.value} />
<Button onClick={this.handleClick} id="zero" value={"0"} />
<Button onClick={this.handleClick} id="one" value={"1"} />
<Button onClick={this.handleClick} id="two" value={"2"} />
<Button onClick={this.handleClick} id="three" value={"3"} />
<Button onClick={this.handleClick} id="four" value={"4"} />
<Button onClick={this.handleClick} id="five" value={"5"} />
<Button onClick={this.handleClick} id="six" value={"6"} />
<Button onClick={this.handleClick} id="seven" value={"7"} />
<Button onClick={this.handleClick} id="eight" value={"8"} />
<Button onClick={this.handleClick} id="nine" value={"9"} />
<Button onClick={this.handleClick} id="decimal" value={"."} />
<Button onClick={this.handleClick} id="equals" value={"="} />
<Button onClick={this.handleClick} id="clear" value={"clear"} />
<Button onClick={this.handleClick} id="add" value={"+"} />
<Button onClick={this.handleClick} id="subtract" value={"-"} />
<Button onClick={this.handleClick} id="multiply" value={"*"} />
<Button onClick={this.handleClick} id="divide" value={"/"} />
</div>
);
}
}
export default Calculator;
Upvotes: 1
Views: 157
Reputation: 7844
A few pointers...
value
to be a string, make sure you don't change it to a number anywhere. You're doing this when id === 'clear'"00"
at the beginning of value
, use startsWith
, not includes
.setState
and the new state depends on the previous state, you must first access the state's previous value. The rationale for this is in the docs.@daniel-hilgarth provides the correct way to use setState
in this case.
Remove leading zero:
this.setState(prevState => ({
value: `${prevState.value}${result}`.replace(/^0+\B/, "")
}));
There's all sorts of ways to do this. The regex above will identify leading zeros. For the case where you have only "0"
, it doesn't match at all because "0"
followed by a end of string (or boundary) doesn't match the regex which is "0"
followed by "not a word boundary".
Upvotes: 2
Reputation: 174329
result
will always contain just a single digit. What you want is to add the new digit to the existing value and only then replace:
this.setState(prevState => ({ value: (prevState.value + result).replace("00", "0") }));
However, this code is buggy, because you would never be able to enter 100
, it would always be changed to 10
.
So the correct logic would be to add a start anchor:
this.setState(prevState => ({ value: (prevState.value + result).replace(/^00/, "0") }));
UPDATE:
To achieve your actual goal, you can use something like the following (not the cleanest code, but should get my point across):
import React from "react";
const availableButtons = [
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
".",
"=",
"clear"
];
const operators = ["+", "-", "*", "/"];
class Calculator extends React.Component {
constructor(props) {
super(props);
this.state = { values: [], value: "", currentNumber: "" };
this.handleClick = this.handleClick.bind(this);
}
handleClick(value) {
if (value === "clear") {
this.setState({ values: [], value: "", currentNumber: "" });
} else if (value === "=") {
this.setState({
value: eval(this.state.value),
values: [],
currentNumber: ""
});
} else {
if (operators.indexOf(value) !== -1) {
this.setState(prevState => ({
values: [...prevState.values, prevState.currentNumber, value],
currentNumber: "",
value: prevState.value + value
}));
} else {
this.setState(prevState => {
const currentNumber = this.formattedNumber(
prevState.currentNumber,
value
);
const newValue = prevState.values.join("") + currentNumber;
return {
currentNumber,
value: newValue
};
});
}
}
}
formattedNumber(previousNumber, newSymbol) {
if (!previousNumber && previousNumber !== 0) return newSymbol;
if (
previousNumber.length === 1 &&
previousNumber === "0" &&
newSymbol !== "."
) {
return newSymbol;
} else {
return previousNumber + newSymbol;
}
}
render() {
return (
<div id="container">
{this.state.value}
<br />
{availableButtons.concat(operators).map(x => (
<button onClick={() => this.handleClick(x)} key={x}>
{x}
</button>
))}
</div>
);
}
}
export default Calculator;
Upvotes: 2
Reputation: 2192
You can change this line
this.setState({ value: this.state.value + result.replace("00", "0") });
to this
let num = this.state.value + Number(result);
this.setState({ value: Number(num).toString()});
I guess that will solve.
Upvotes: 0