Хуки - это новые функции React 16.8. Они позволяют нам писать функции, связанные с компонентами класса, такие как состояние использования в функциональном компоненте.

Лично я, когда начал использовать хуки, я нашел их интересными и очень простыми для понимания. Я думаю, что хуки станут де-факто способом написания React в будущем.

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

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

Вы можете найти демонстрацию CodeSandbox в конце сообщения, если не хотите повторять шаги

Шаги

  1. Определите состояние - как выглядят данные
  2. Создание статического макета без взаимодействия
  3. Добавить события / взаимодействия

Определите состояние

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

{name: “Some item”, price: 123}

Затем мы хотим управлять динамическими входами или элементами, поэтому мы помещаем их в массив

[
  {name: “Some item”, price: 123},
  {name: “Other item”, price: 456},
  {name: “Final item”, price: 200}
]

Теперь мы, наконец, построим форму состояния входных элементов.

Создайте статический макет

Теперь мы создаем статический CostTable компонент. Я объясню код ниже

Хуки не работают внутри классов

Хуки позволяют нам использовать состояние в функциональных компонентах (ранее называвшихся компонентами без состояния - больше не 😝). Следует напомнить, что хуки не работают внутри классов. Посетите официальную React docs для получения дополнительной информации.

Использование хука State:

const [costs, setCosts] = useState(_defaultCosts);

Приведенный выше код позволяет нам объявить переменную состояния с помощью хука useState. Вызов useState возвращает набор из двух переменных, в этом случае мы называем их costs и setCosts (вы можете называть их как хотите), одна - это само текущее состояние, а другая - функция для его обновления. Это эквивалентно this.state.costs и this.setState в компонентах класса. Синтаксис называется деструктуризация.

Мы передаем аргумент _defaultCosts для useState в качестве начального состояния. В отличие от классов, состояние может быть любым: числом, строкой, объектом или массивом.

Функция render просто возвращает набор jsx, который описывает таблицу с заголовком, заголовком таблицы, телом таблицы и нижним колонтитулом таблицы.

Мы получаем доступ к переменной состояния так же, как и к обычной. Вызов costs.map((item, index) => (...)) берет каждый элемент из массива costs и отображает два ввода, один для названия стоимости, другой для цены.

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

Добавить события / взаимодействия

Обработка изменения ввода

Теперь входные данные отображают значения по умолчанию из элементов массива, но когда мы что-то вводим, значение не меняется. Причина в том, что мы не определили метод обработки изменения ввода onChange={null}.. Определим его сейчас, непосредственно перед rendermethod

const handleCostsChange = event => {
  const _tempCosts = […costs];
  _tempCosts[event.target.dataset.id][event.target.name] = event.target.value;
  setCosts(_tempCosts);
};

и замените onChange={null} наonChange={handleCostsChange} для двух входных элементов внутри table-body

Первая строка const _tempCosts = [...costs]; делает копию текущего costs состояния и присваивает его _tempCosts, затем мы можем изменить _tempCosts по своему усмотрению.

event.target.dataset.id - это index из data-id={index}, который является индексом элемента в состоянии массива costs (подробнее о наборе данных HTMLElement см. Здесь). event.target.name либо name, либо price предоставляется <input name="..." />. Таким образом мы получаем доступ к нужному элементу в состоянии costs. Например, когда мы вносим изменения или вводим во вторую строку таблицы затрат и в столбец цен, этот элемент изменяется как _tempCosts[1]['price'] = <typed price>

Наконец, мы можем вызвать setCosts(_tempCosts) из const [costs, setCosts] = useState(_defaultCosts), который мы определили с самого начала, чтобы обновить состояние costs с новыми затратами.

Добавить дополнительную стоимость

Под этими входами в макете мы определили +button <button onClick={null}> + </button> Let define addNewCost method

const addNewCost = () => {
  setCosts(prevCosts => […prevCosts, { name: “”, price: 0 }]);
};

и установите onClick на этот метод

<button onClick={addNewCost}>+</button>

Внутри метода addNewCost мы снова используем setCosts.. На этот раз мы передаем обратный вызов, который принимает текущее состояние затрат и возвращает новое. При нажатии кнопки + мы добавляем новый элемент с пустым именем и ценой 0 в состояние costs. После обновления costsstate React перерисовывает нашу таблицу с новой строкой. Это похоже на this.setState(prevState => newStateBasedOnPrevState) в классах.

Рассчитайте общую сумму

Наконец, мы вычисляем общую сумму и отображаем ее в нижнем колонтитуле. Давайте определимся с методом:

const getTotalCosts = () => {
  return costs.reduce((total, item) => {
    return total + Number(item.price);
  }, 0);
};

и отобразить его в нижнем колонтитуле:

<div className="table-footer">
  <div className="table-row">
    <div className="table-data">
      <div>Total</div>
    </div>
    <div className="table-data">
      <div>{getTotalCosts()}</div>
    </div>
  </div>
</div>

getTotalCosts используйте Array’sreduce для накопления окончательной общей суммы затрат. Подробнее про reduce здесь

Заворачивать

У нас есть все ингредиенты для нашей таблицы затрат. Соберем их все вместе.

Заключение

Итак, мы просто используем Hook для создания простой динамической формы.

Ниже вы можете найти демонстрацию CodeSandbox.



Если вы найдете эту публикацию полезной, дайте мне аплодисменты 👏 😉

Купи мне кофе https://www.buymeacoffee.com/binhtran 🤝

Также проверьте: