Ограничение количества входов

Я пытаюсь сделать калькулятор 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;
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
0
97
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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;

Рабочий образец

Извините, но это тоже не работает! Он просто отключает любой ввод любого числа.

Hernan Ariel 21.10.2018 17:36

Спасибо. Он работает, но добавляет одну дополнительную проблему: он по-прежнему позволяет «01» и так далее, вместо того, чтобы заменять его просто «1». Я пытался обернуть его вокруг Number, но это вызывает другую проблему, которая отключает "+" и так далее. Я застрял здесь, не думал, что это будет так сложно.

Hernan Ariel 21.10.2018 18:03

Что ж, вам нужно подумать о том, чего вы здесь пытаетесь достичь. Вы хотите запретить начальные нули в строке, которая может содержать произвольное количество математических операторов. Правильный способ - сохранить это не как простую строку, а как серию объектов, например. числа и операторы, а затем просто отформатируйте его в строку для отображения

Daniel Hilgarth 21.10.2018 18:08

Вы имеете в виду сохранение каждого результата каждого ввода до того, как они изменят состояние?

Hernan Ariel 21.10.2018 18:12

123 + 789/555 следует хранить как что-то вроде [{type: 'Number', value: '123'},{type:'operator', value: '+'},{type: 'Number', value: '789'},{type:'operator', value: '/'},{type: 'Number', value: '555'},]

Daniel Hilgarth 21.10.2018 18:20

Поэтому вам нужно запомнить текущий номер, пока пользователь вводит числа, а затем сохранить его в массиве, когда пользователь вводит оператор.

Daniel Hilgarth 21.10.2018 18:21

Честно говоря, я понятия не имею, как это сделать. Возможно ли это в React до обновления состояния? Я думаю, console.infoging много.

Hernan Ariel 21.10.2018 18:25

Нет, текущий номер - это тоже состояние

Daniel Hilgarth 21.10.2018 18:41

Спасибо. Кажется, он работает, но мне было бы неудобно использовать его, поскольку это почти полностью ваш код (это кажется неэтичным). Думаю, я собираюсь придерживаться RegEx (посмотрю, могу ли я добавить «заменить его числом, если оно 0 + число» и выработать решение, когда оно состоит из двух десятичных запятых вместе)

Hernan Ariel 21.10.2018 19:23

Ничего страшного, пользоваться можно. Однако попытайтесь понять, что он делает, вы кое-чему научитесь по пути. И, узнав, что он делает, вы можете адаптировать его к своему собственному стилю и сделать его своим собственным.

Daniel Hilgarth 21.10.2018 19:25

Вы можете изменить эту строку

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/…

Daniel Hilgarth 21.10.2018 17:37

Что сказал Даниэль.

Hernan Ariel 21.10.2018 17:40

Спасибо, но это приносит только больше проблем, так как теперь вы не можете нажимать какие-либо элементы ввода, кроме числа (например, «+» и т. д.)

Hernan Ariel 21.10.2018 17:50
Ответ принят как подходящий

Несколько указателей ...

  • Если вы хотите, чтобы value был строкой, убедитесь, что вы нигде не изменили ее на число. Вы делаете это, когда id === 'clear'
  • Если вы хотите проверить только "00" в начале value, используйте startsWith, а не includes.
  • Если вы используете setState и новое состояние зависит от предыдущего состояния, вы должны сначала получить доступ к предыдущему значению состояния. обоснование для этого находится в документации.

@ daniel-hilgarth предоставляет правильный способ использования setState в этом случае.

Удалить ведущий ноль:

this.setState(prevState => ({
  value: `${prevState.value}${result}`.replace(/^0+\B/, "")
}));

Есть много способов сделать это. Регулярное выражение выше идентифицирует ведущие нули. В случае, когда у вас есть только "0", он вообще не совпадает, потому что "0", за которым следует конец строки (или граница), не соответствует регулярному выражению, которое является "0", за которым следует «не граница слова».

Спасибо за указатели. Я попробовал подход Дэниела, но он вообще отключил любой ввод.

Hernan Ariel 21.10.2018 17:46

Тело лямбда-выражения должно иметь оператор возврата ИЛИ быть заключено в скобки, чтобы сообщить JavaScript, что фигурные скобки представляют объект JavaScript, а не тело кода. Попробуйте this.setState(prevState => ({ value: `${prevState.value}${result}`.replace(/^00/, "0") }));

Ryan H. 21.10.2018 17:53

Такой вид работает, но по-прежнему позволяет «01» вместо «1». Не думал, что это будет так сложно.

Hernan Ariel 21.10.2018 17:56

Вам просто нужно продолжать его настраивать. Такова жизнь программиста. Я обновил свой ответ. Просто продолжайте его улучшать.

Ryan H. 21.10.2018 18:13

Спасибо. Может ли работать RegEx? (Например, обнаруживает 0 + Int и просто заменяет его на Int)

Hernan Ariel 21.10.2018 18:15

Решение действительно использует регулярное выражение, а ^0+ означает «начинается с одного или нескольких нулей». Конечно, на самом деле вы хотели «один или несколько нулей, кроме тех случаев, когда он сам по себе просто ноль», поэтому я добавил || "0", что означает, что если вы получите пустую строку, сделайте ее 0 вместо этого.

Ryan H. 21.10.2018 18:48

Мне просто нужно увидеть, как превратить это в «начать с еще одним нулем, кроме тех случаев, когда он сам по себе равен нулю, И отбросить ноль, когда за ним следует число». Я пробовал использовать ParseInt и добавлять исключения для операторов, но тоже не сдвинулся с места.

Hernan Ariel 21.10.2018 18:51

Я имею в виду, могу ли я разработать RegEx, которое обнаруживает «01» и возвращает «1»? это возможно?

Hernan Ariel 21.10.2018 19:29

Другие вопросы по теме