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

Создаем калькулятор-конвертер на базе React. Часть 5: Добавляем историю результатов

1 комментарий
Создаем калькулятор-конвертер на базе React. Часть 5: Добавляем историю результатов

Очередной этап разработки конвертера-калькулятора на базе Реакта. В этом уроке создадим компонент для сохранения всех результатов вычисления, выполненных за время использования калькулятора. 

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

Цели задачи

Мотивация за созданием подобной функции следующая: в большинстве мобильных и дескоптных калькуляторов нет нормального механизма для просмотра предыдущих результатов расчетов. То есть если посчитали что-то, а потом посчитали что-то еще, то предыдущий результат будет заменен новым и вернуться к нему не получится. Я не один десяток раз натыкался на сценарии, когда было бы удобно иметь под рукой результат вычисления, выполненного несколько минут назад. И очень раздражает, что нельзя просто взять уже готовый расчет из того же интерфейса и воспользоваться им в новых подсчетах. Ну или хотя бы иметь возможность вручную переписать существующее значение в новый пример. 

Справедливости ради стоит отметить, что такая функциональность есть в некоторых приложениях (Calzy, например). Но это большая редкость, поэтому мы сделаем свой вариант. 

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

Создаем компонент History

Начнем с создания специальной функции History, которая будет содержать в себе все элементы с результатами предыдущих расчетов и отображать их в интерфейсе приложения прямо над строкой ввода значений.

Сначала объявляем функцию History в компоненте Calculator (именно в нем, потому что мы хотим, чтобы история была доступна как в визуальном режиме расчетов, так и в смарт-режиме, а в перспективе туда можно сохранять еще и результаты вычислений, связанных с конвертацией). 

В коде функция будет выглядеть так: 

function History(props) { }

Компонент History

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

const [history, setHistory] = useState([])

Новое состояние в компоненте Calculator

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

<Box> <History data={history} /> </Box>

Верстка блока Calculator

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

const results = props.data.map(result => { return <Button key={result}>{result}</Button> })}

Переменная results в компоненте History

Из компонента History нужно вернуть весь массив с вычислениями, что там хранится. То есть переменную results, сформированную выше. 

return (<Box> {result} </Box>)

Метод return в компоненте History

Готово. Только вот история у нас пустая и пока что в интерфейсе ничего не отображается. Далее мы это изменим. 

Добавляем колбэки для обновления элементов в компоненте History

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

Функция updateHistory

  • Переходим к компоненту Calculator и объявляем там функцию updateHistory с аргументом calcResult. 

    function updateHistory(calcResult) { }
  • В теле функции переназначаем history на обновленный массив, объединенный с существующим массивом, который производит расчет текущего примера при помощи функции eval. 

    setHistory(history.concat(eval(calcResult)))

Аргументом calcResult будет текущее состояние расчетов в одном из компонентов калькулятора (InputCalc или ClickCalc).

Далее необходимо реализовать колбэк, то есть метод, обращающийся к другому компоненту Реакта и возвращающий значение для запуска какой-либо логики в компоненте, который выполнил запрос. Проще говоря, передадим функцию через пропсы, чтобы задействовать updateHistory внутри Calculator, но из InputCalc или ClickCalc.

Для этого отправим в ClickCalc пропс с названием onClick. 

<ClickCalc onClick={updateHistory} />

Конструкция Switch

Теперь внутри ClickCalc нужно дописать аргумент props, так как раньше его в нашем приложении не существовало. 

Аргумент props в компоненте clickCalc

И метод updateHistory привяжем к кнопке «Равно». Мне такой подход кажется наиболее логичным. С помощью него мы получаем нужный результат и тут же отправляем его в историю вычислений. 

props.onClick(counts)

Обновленная кнопка равенства в ClickCalc

А вот с InputCalc немного сложнее. Передать туда функцию updateHistory можно таким же способом. Просто укажем в качестве пропса:

<InpurCalc onKeyDown={updateHistory} />

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

Поэтому находим внутри компонента InputCalc элемент Input, отвечающий за отображение символов в строке подсчетов. Добавляем к нему функцию sendDataToHistory (которую мы создадим чуть позже), срабатывающую по нажатию на клавиатуре. Получится такой код: 

<Input onKeyDown={(e) => {sendDataToHistory}}

Метод onKeyDown

Сейчас наш код не годится, потому что он будет реагировать на нажатие любой кнопки на клавиатуре. Мы должно исключить все клавиши, кроме Enter, поэтому внутри функции sendDataToHistory реализуем проверку нажимаемой кнопки на соответствие нужной нам. И если проверка завершится успешно, то сработает метод updateHistory из родительского компонента с переменной counts в качестве аргумента. 

function sendDataToHistory(e) { if (e.nativeEvent.key == "Enter") { props.onKeyDown(counts) } }

Функция sendDataToHistory

Готово. Теперь по нажатию на Enter будет срабатывать вычисление и моментальная отправка данных в History. Останется лишь прицепить к этому методу еще и зачистку строки расчетов, если вы хотите каждый раз начинать сначала по нажатию на Enter. Для этого в функцию sendDataToHistory надо добавить метод setCount, обнуляющий значение состояния компонента. 

setCounts('')

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

Проверка количества элементов в History

Добавим в метод updateHistory проверку количества элементов в массиве history. 

if (history.length > 6) {history.shift()}

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

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

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

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

Комментарии

Дима Пелехов 0
16 июля в 18:51
Добрый день. Работаю с ноутбука. И у меня почему-то не работает расчёт результатов в InputCalc при нажатии на Enter.
С помощью соцсетей
У меня нет аккаунта Зарегистрироваться
С помощью соцсетей
У меня уже есть аккаунт Войти
Инструкции по восстановлению пароля высланы на Ваш адрес электронной почты.
Пожалуйста, укажите email вашего аккаунта
Ваш баланс 10 ТК
1 ТК = 1 ₽
О том, как заработать и потратить Таймкарму, читайте в этой статье
Чтобы потратить Таймкарму, зарегистрируйтесь на нашем сайте