Реклама ООО Таймвэб
Реклама ООО Таймвэб
Реклама ООО Таймвэб

Создаем калькулятор-конвертер на базе React. Часть 3: Автоматический подсчет результатов

Обсудить
Создаем калькулятор-конвертер на базе React. Часть 3: Автоматический подсчет результатов

Продолжаем расширять функциональность калькулятора на базе React. На этот раз добавим возможность проводить расчеты в автоматическом режиме при вводе выражений напрямую в строку. Фактически мы повторим функциональность калькулятора поисковой строки в браузерах и Spotlight (глобальная поисковая система в macOS и iOS). 

Расчет будет производиться функцией eval в соответствии с базовыми правилами математики. 

Предыдущий материал: Калькулятор-конвертер на базе React. Часть 2: Базовый интерфейс

Добавляем новый компонент

За новый тип расчетов будет отвечать отдельная функция, обрисовывающая собственную часть интерфейса, а именно строку для ввода текста. 

Поэтому сначала нам нужно импортировать в свое приложение новый элемент из Чакры – Input. Это кастомизируемое HTML-поле для ввода текста, цифр и другого контента. 

import { Input } from '@chakra-ui/react'

Импорт блоков Chakra UI

После этого создадим компонент InputCalc, где и будет отображаться строка для ввода текста. 

function InputCalc (props) { }

Создание нового компонента в Реакте

В теле новой функции нужно сразу задать состояние. Отдельное поле для подсчетов здесь не используется, поэтому в нашем случае будет только состояние result с результатом расчетов. По умолчанию оно должно представлять собой пустую строку. 

const [result, setResult] = useState('')

И в конце функции не забываем вернуть строку для ввода текста. 

return ( <Input type="text"> </Input> )

Пустое поле Input в из Chakra UI

Комьюнити теперь в Телеграм
Подпишитесь и будьте в курсе последних IT-новостей
Подписаться

Функция подсчета результатов и вывод переменной result в интерфейс

Сам по себе калькулятор ничего считать не будет, поэтому нам нужна отдельная функция, которая будет производить вычитания, сложения и другие операции по мере ввода текста. Сразу запишем ее в поле Input. 

onInput={ (e) => {updateCounts(e)}}

Эта запись обозначает, что при любом изменении текста в поле Input будет активироваться функция updateCounts (мы объявим ее чуть позже), а ее аргументом будет непосредственно событие input (ввод или удаление символов из соответствующей строки). 

Также мы добавим блок Text, чтобы отобразить на экране результат вычислений – переменную result. 

<Text> {result} </Text>

Функция изменения контента в Input при введении новых символов

Следующий этап – создание функции updateCounts, подсчитывающей результат выражения в нашем Input. 

function updateCount (e) { }

Промежуточное состояние компонента InputCalc

Тут мы сразу сталкиваемся с проблемой – если использовать eval при каждом onInput, то программа сломается после введения любого знака, непохожего на число. Нажав на +, вы спровоцируете критическую ошибку и все приложение рухнет. Поэтому в теле updateCounts нужно сразу прописать проверку на соответствие введенных символов «безопасным» знакам. 

Функция updateCounts

  • Создаем переменную expressions, где будет регулярное выражение с символами, которых необходимо избегать. 

    const expressions = /\+|\-|\/|\*|=|[A-z]| /
  • Объявляем переменную lastNumber, хранящую значение последнего введенного символа в Input-блоке (e.target здесь – это HTML-элемент, связанный с Input). 

    const lastNumber = e.target.value[e.target.value.length - 1]
  • Прописываем условие проверки. Если последний знак входит в лист запрещенных, то мы не производим расчет. 

    if (expressions.test(lastNumber)) return
  • А если не входит, то считаем результат. 

    else setResult(eval(e.target.value))

Блок updateCounts

Можно пойти от обратного и проверять, является ли последний символ числом. Если нет, то работу программы блокируем, если является – производим расчет. 

Альтернативная функция updateCounts

Получится такое выражение. Мы убрали все знаки, кроме числительных, и добавили закрывающуюся скобку. Она нужна, чтобы пользователь мог настраивать порядок расчетов (eval считает значения в скобках в первую очередь, а потом берется за остальные в зависимости от приоритета знаков). 

Такой подход лучше (меньше кода, меньше шансов сломать программу). Но проблема в том, что наше приложение предпринимает попытку сделать расчет каждый раз, когда пользователь вводит число. Если до этого он ввел знак доллара или десять плюсов подряд, то расчет производиться не будет. Программа не «упадет», но будет сыпать десятками ошибок в консоль, что не очень хорошо. 

В такой ситуации можно воспользоваться методикой перехвата контроля над формами в Реакте. Мы можем забрать у стандартных элементов возможность управлять содержимым форм и самостоятельно заменять значения в них. Это позволяет запретить ввод тех или иных символов. В нашем случае это как раз то, что нужно, чтобы пользователь программы не мог случайно ввести два плюса и начать генерировать ошибки.

Создаем новое состояние counts, где будет храниться информация о строке ввода для нашего калькулятора. Значением по умолчанию можно оставить пустую строчку. 

const [counts, setCounts] = useState('')

Состояние result в React-компоненте

Заменим значение value в Input со стандартного на то, что необходимо нам, а именно на значение нового состояния counts, которое мы добавили выше. 

<Input value={counts} />

Верстка компонента InputCalc

Используем ту же переменную expressions (можно дополнить ее и другими запрещенными знаками, если надо). 

Переменная expressions

Корректируем переменную lastNumber, чтобы она показывала не последний символ в строке, а предпоследний (это необходимо, потому что в противном случае функция не даст указать запрещенный знак, даже если последнее значение в строке – это число). 

const lastNumber = e.target.value[e.target.value.length - 2]

Переменная lastNumber

Создаем дополнительную проверку, чтобы убедиться в том, что мы вводим корректные символы и их можно смело добавлять в строку для расчета результата.

Проверка вводимых значений

  • Сначала проверяем, не вводится ли повторно запрещенный знак. Такая многоэтапная проверка позволяет исключить практически любое неадекватное поведение калькулятора. 

    if (expressions.test(lastNumber) && expressions.test(e.nativeEvent.data) && e.nativeEvent.data != null) return
  • Потом убеждаемся в том, что в строке нет «опасных» знаков и можно смело производить расчет при помощи eval. 

    if (!expressions.test(e.nativeEvent.data)) setResult(eval(e.target.value))
  • А потом уже добавляем контент в строку. 

    setCounts(e.tager.value)

В этом случае тоже можно пойти от обратного и проверять вводимые символы на соответствие стандартам безопасности для подсчета в eval. 

Альтернативная расширенная функция updateCounts

  • Заменяем expressions на числовые выражения. 

    const expressions = /[0-9]/
  • В первой условии подменяем проверку на true проверкой на false. 

    if (!expressions.test(lastNumber) && !expressions.test(e.nativeEvent.data) && e.nativeEvent.data != null) return
  • Во втором условии все наоборот. 

    if (expressions.test(e.nativeEvent.data)) setResult(eval(e.target.value))
  • Оставляем обновление поля Input. 

    setCounts(e.target.value)

Готово. Осталось добавить калькулятор в основной компонент, чтобы он отображался в интерфейсе. Просто вписываем <InputCalc /> в компонент App.

Внедрение InputCalc в основной интерфейс приложения

Вот как по итогу будет выглядеть код программы в return-блоке компонента App:

Код калькулятора

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

Смарт-калькулятор в браузере

Вместо заключения

Мы добавили первую умную функцию в наш калькулятор. Теперь необязательно тыкать по кнопкам, чтобы быстро посчитать выражение. Далее мы продолжим изучать Реакт, будем решать мелкие проблемы калькулятора и развивать его возможности.

Продолжение: Калькулятор-конвертер на базе React. Часть 4: Декомпозиция и мелкие исправления

Hello World! Гайды и обзоры для девелоперов разных мастей.

Комментарии

С помощью соцсетей
У меня нет аккаунта Зарегистрироваться
С помощью соцсетей
У меня уже есть аккаунт Войти
Инструкции по восстановлению пароля высланы на Ваш адрес электронной почты.
Пожалуйста, укажите email вашего аккаунта
Ваш баланс 10 ТК
1 ТК = 1 ₽
О том, как заработать и потратить Таймкарму, читайте в этой статье
Чтобы потратить Таймкарму, зарегистрируйтесь на нашем сайте