Я пытаюсь сделать калькулятор React. В основном это делается, но у меня есть одна проблема, которую я не знаю, как исправить: я не хочу, чтобы пользователи вводили выражения, начинающиеся более чем с одного «0» И такие выражения, как «01», должны быть заменены просто «1». Я думал об использовании строковых методов, чтобы ограничить это, но это не сдвинулось с места. Обновлено: Я знаю, почему мое решение не работает (на входе никогда не будет больше одного нуля), но я не знаю другого способа исправить это.
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.info(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;





result всегда будет содержать только одну цифру. Вы хотите добавить новую цифру к существующему значению и только потом заменить:
this.setState(prevState => ({ value: (prevState.value + result).replace("00", "0") }));
Однако этот код содержит ошибки, потому что вы никогда не сможете ввести 100, он всегда будет изменен на 10.
Итак, правильная логика - добавить начальный якорь:
this.setState(prevState => ({ value: (prevState.value + result).replace(/^00/, "0") }));
Обновлено:
Чтобы достичь своей фактической цели, вы можете использовать что-то вроде следующего (не самый чистый код, но он должен донести мою мысль):
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;
Спасибо. Он работает, но добавляет одну дополнительную проблему: он по-прежнему позволяет «01» и так далее, вместо того, чтобы заменять его просто «1». Я пытался обернуть его вокруг Number, но это вызывает другую проблему, которая отключает "+" и так далее. Я застрял здесь, не думал, что это будет так сложно.
Что ж, вам нужно подумать о том, чего вы здесь пытаетесь достичь. Вы хотите запретить начальные нули в строке, которая может содержать произвольное количество математических операторов. Правильный способ - сохранить это не как простую строку, а как серию объектов, например. числа и операторы, а затем просто отформатируйте его в строку для отображения
Вы имеете в виду сохранение каждого результата каждого ввода до того, как они изменят состояние?
123 + 789/555 следует хранить как что-то вроде [{type: 'Number', value: '123'},{type:'operator', value: '+'},{type: 'Number', value: '789'},{type:'operator', value: '/'},{type: 'Number', value: '555'},]
Поэтому вам нужно запомнить текущий номер, пока пользователь вводит числа, а затем сохранить его в массиве, когда пользователь вводит оператор.
Честно говоря, я понятия не имею, как это сделать. Возможно ли это в React до обновления состояния? Я думаю, console.infoging много.
Нет, текущий номер - это тоже состояние
Спасибо. Кажется, он работает, но мне было бы неудобно использовать его, поскольку это почти полностью ваш код (это кажется неэтичным). Думаю, я собираюсь придерживаться RegEx (посмотрю, могу ли я добавить «заменить его числом, если оно 0 + число» и выработать решение, когда оно состоит из двух десятичных запятых вместе)
Ничего страшного, пользоваться можно. Однако попытайтесь понять, что он делает, вы кое-чему научитесь по пути. И, узнав, что он делает, вы можете адаптировать его к своему собственному стилю и сделать его своим собственным.
Вы можете изменить эту строку
this.setState({ value: this.state.value + result.replace("00", "0") });
к этому
let num = this.state.value + Number(result);
this.setState({ value: Number(num).toString()});
Думаю, это решит.
1. Это не решает проблему и 2. Никогда не обращайтесь к предыдущему состоянию в setState таким образом. Всегда используйте перегрузку с обратным вызовом: teamtreehouse.com/community/…
Что сказал Даниэль.
Спасибо, но это приносит только больше проблем, так как теперь вы не можете нажимать какие-либо элементы ввода, кроме числа (например, «+» и т. д.)
Несколько указателей ...
value был строкой, убедитесь, что вы нигде не изменили ее на число. Вы делаете это, когда id === 'clear'"00" в начале value, используйте startsWith, а не includes.setState и новое состояние зависит от предыдущего состояния, вы должны сначала получить доступ к предыдущему значению состояния. обоснование для этого находится в документации.@ daniel-hilgarth предоставляет правильный способ использования setState в этом случае.
Удалить ведущий ноль:
this.setState(prevState => ({
value: `${prevState.value}${result}`.replace(/^0+\B/, "")
}));
Есть много способов сделать это. Регулярное выражение выше идентифицирует ведущие нули. В случае, когда у вас есть только "0", он вообще не совпадает, потому что "0", за которым следует конец строки (или граница), не соответствует регулярному выражению, которое является "0", за которым следует «не граница слова».
Спасибо за указатели. Я попробовал подход Дэниела, но он вообще отключил любой ввод.
Тело лямбда-выражения должно иметь оператор возврата ИЛИ быть заключено в скобки, чтобы сообщить JavaScript, что фигурные скобки представляют объект JavaScript, а не тело кода. Попробуйте this.setState(prevState => ({ value: `${prevState.value}${result}`.replace(/^00/, "0") }));
Такой вид работает, но по-прежнему позволяет «01» вместо «1». Не думал, что это будет так сложно.
Вам просто нужно продолжать его настраивать. Такова жизнь программиста. Я обновил свой ответ. Просто продолжайте его улучшать.
Спасибо. Может ли работать RegEx? (Например, обнаруживает 0 + Int и просто заменяет его на Int)
Решение действительно использует регулярное выражение, а ^0+ означает «начинается с одного или нескольких нулей». Конечно, на самом деле вы хотели «один или несколько нулей, кроме тех случаев, когда он сам по себе просто ноль», поэтому я добавил || "0", что означает, что если вы получите пустую строку, сделайте ее 0 вместо этого.
Мне просто нужно увидеть, как превратить это в «начать с еще одним нулем, кроме тех случаев, когда он сам по себе равен нулю, И отбросить ноль, когда за ним следует число». Я пробовал использовать ParseInt и добавлять исключения для операторов, но тоже не сдвинулся с места.
Я имею в виду, могу ли я разработать RegEx, которое обнаруживает «01» и возвращает «1»? это возможно?
Извините, но это тоже не работает! Он просто отключает любой ввод любого числа.