(перевод-конспект статьи от Tania Rascia + текст/код от себя)
(первая часть «Знакомство с хуками» здесь)
Напомню про разницу между формой создания компонентов в react:
Как вы знаете многие фичи доступны лишь для класса, например — state и lifecycle-методы. Хуки добавляют эти возможности для stateless-компонентов (функциональных компонентов, компонентов созданных с помощью function).
В данном посте мы сделаем CRUD-приложение только на хуках без классов, чтобы научиться использовать react hooks. Мы будем использовать state хук и effect хук на функциональных компонентах.
Можно стартануть проект с помощью CRA или взять этот репозиторий за основу. Ветка — 1.prepair
В репозитории находятся стартовые файлы, среди которых:
src/App.js
Вспоминаем как работает useState хук
В первой части, мы уже разобрались с useState хуком.
Следовательно, глупый пример со счетчиком выглядит так:
Исходный код (ветка 2-count-example)
Настраиваем внешний вид
Добавим статичных данных в App и отрисуем табличку (UserTable) и форму добавления нового пользователя (AddUserForm).
src/tables/UserTable.js
src/forms/AddUserForm.js
src/App.js
Форма сейчас, разумеется не работает, о чем у нас есть предупреждение на скрине.
Добавление пользователя
Подытожим: у нас есть «статичные» данные, есть компонент добавления юзера. Что нам нужно?
- научиться изменять usersData в компоненте App (usersTable сразу же перерисуется) как-нибудь;
- научиться изменять usersData через компонент-форму (то есть, передать туда коллбэк-функцию, которую вызывать на submit, и изменять usersData в App);
- научиться в AddUserForm работать с формой через хуки;
Начнем с первого пункта:
src/App.js
Теперь можем выполнить в консоли:
setUsers([{ id: 3, name: 'Link', username: 'thelegend' }])
Функция изменения данных — работает. Теперь необходимо передать ее в AddUserForm, но при этом не перезатирать массив, а добавлять в него новые элементы. Так же, сразу заполним корректно значение параметра id.
Функцию передали, осталось вызывать ее на submit, но для начала наладим работу формы:
Форма работает, и теперь мы готовы добить submit:
В принципе, если вы знакомы с тем как работает передача props в реакте, вы должны уловить связь. Если нет — пишите вопросы в комментариях, разберемся.
Исходный код (ветка 3-add-user)
Удаление пользователя
Порядок решения задачи:
- написать функцию для удаления (разместить в App);
- передать ее в качестве props в UserTable;
- в UserTable «повесить» эту функцию на кнопку;
Удаление реализуем через filter
src/App.js
src/tables/UserTable.js
Обновление пользователя
Из статьи Tania:
Финальный кусочек пазла — это редактирование пользователя. Этого можно достичь так же, как и в случае с добавлением пользователя, однако нам нужно уметь идентифицировать какой пользователь в данный момент редактируется. В компонентах созданных с помощью class, мы могли сделать это в componentDidUpdate, но сейчас мы будем использовать Effect Hook. Effect hook — это как-будто скомбинированный componentDidMount и componentDidUpdate.
Таня, предлагает нам использовать новый компонент EditUserForm с подставленными туда name и username, в момент, когда будет нажата кнопка edit.
Так же нам придется добавить флаг «редактируется/не редактируется», какой пользователь сейчас на «редактировании» и начальное значение полей формы в App.
src/forms/EditUserForm.js
Добавим в App:
- флаг
editing
; - информацию о том, какой пользователь сейчас редактируется (
currentUser
); - функцию
editRow
, которая будет вызываться по клику на кнопку Edit и будет подставлять пользователя в форму редактирования; - функцию
updateUser
, которая, непосредственно, будет обновлять пользователя; - развилку в render, чтобы показывать форму редактирования или форму добавления, в зависимости от
editing
;
src/App.js
src/tables/UserTable.js
(выше в руководстве был небольшой косяк — имена файлов компонентов в директориях начинались с маленькой буквы, исправлено в исходном коде ниже)
Исходный код на данный момент (ветка 5-edit-user)
Внимание, в данный момент редактирование пользователя работает некорректно и мне бы хотелось, чтобы вы это проверили. Так будет легче понять заключительную часть.
Использование Effect Hook
Проблема на данный момент: если кликнуть сначала на редактирование одного пользователя, а потом на другого — то данные в форме не изменятся, хотя компонент получает props новые и перерисовывается как нужно. Для проверки, я добавил в шаблон props.currentUser.name
рядом с Name
Логично, что у нас в state компонента (который сделан с помощью хука useState и функции обновления setUser) не приходят новые значения из props.
(для тех, кто работает с react давно, это может быть звоночком в сторону componentWillReceiveProps, а для тех, кто знаком позже — componentDidUpdate).
В чем суть проблемы: мы должны сказать компоненту, что если свойства (props) изменились, то нужно «обновить стейт«. То есть, мы должны каким-то образом в stateless-компоненте использовать componentDidUpdate метод. Здесь на помощь, приходит effect hook.
Бинго!
Осталось слегка подправить работу приложения. Сейчас, если удалить пользователя, который редактируется в данный момент, в форме останутся не актуальные данные. Чтобы ее очистить в момент удаления, достаточно обновить флаг editing
в deleteUser
:
Исходный код (ветка 6-complete)
Дополнительные материалы
- Большой материал от fullstack react с кучей интерактивных примеров на хуках. Он же на русском.
- From Classes to Hooks (react documentation)
Очень хорошая статья.
Единственный вопрос, который остался, как бы выглядела реализация компонента EditForm в качестве классового компонента? Точнее метод componentDidUpdate!
Спасибо Вам огромное! Очень помогло в понимании react))