Вывод результатов работы thunk в компоненте в Redux

На прошлом занятии мы отправили POST-запрос с помощью thunk addProduct. Давайте теперь отобразим результаты его работы в компоненте.

Откроем наше приложение с продуктами, а в нем файл NewProductForm.jsx, поскольку этот компонент ответственен за добавление нового продукта. Посмотрим на строчки с импортом. Заменим импорт экшена productAdded, на импорт thunk addProduct:

products/NewProductForm.jsximport { addProduct } from './productsSlice'

Теперь, поскольку мы не отслеживаем в слайсе статус 'pending' запроса, давайте сделаем так, чтобы пользователь смог нажать на кнопку с сохранением продукта только один раз, ведь нам не нужны те же самые повторные запросы. Для этого заведем еще один локальный стейт:

products/NewProductForm.jsxconst [requestStatus, setRequestStatus] = useState('idle')

Далее после обработчиков и перед функцией onSaveProductClick напишем код, в котором проверим, все ли поля формы у нас заполнены и находится ли статус запроса в 'idle':

products/NewProductForm.jsxconst canBeSaved =
  [name, desc, price, amount, sellerId].every(Boolean) &&
  requestStatus === 'idle'

Затем мы изменим код для onSaveProductClick. Во-первых это будет асинхронная функция и она будет выполняться, если верно вышеприведенное условие:

products/NewProductForm.jsxconst onSaveProductClick = async () => {
  if (canBeSaved) {}
}

Несмотря на то, что мы в слайсе не отслеживаем статус 'rejected', мы все равно можем вывести в консоль ошибку, для этого воспользуемся конструкцией try-catch. Также здесь мы добавим еще и finally, чтобы после выполнения запроса снова установить локальный стейт в 'idle':

products/NewProductForm.jsxconst onSaveProductClick = async () => {
  if (canBeSaved) {
    try {
    } catch (err) {
      console.error(save product error: , err)
    } finally {
      setRequestStatus('idle')
    }
  }
}

С catch и finally блоками мы разобрались, давайте напишем код для блока try. Здесь мы установим локальный статус в 'in pogress', пока нам не вернется какой-нибудь ответ в результате работы thunk, затем отправим наш thunk addProduct. Использовать конструкцию try-catch в зависимости от типа ответа нам поможет функция RTK unwrap, которую он добавляет к возвращаемому промису. Затем, если запрос был успешен мы устанавливаем локальные стейты в их начальные состояния. Полный код для onSaveProductClick будет выглядеть так:

products/NewProductForm.jsxconst onSaveProductClick = async () => {
  if (canBeSaved) {
    try {
      setRequestStatus('in progress')
      await dispatch(
        addProduct({ name, desc, price, amount, seller: sellerId })).unwrap()
      setName('')
      setDesc('')
      setPrice(0)
      setAmount(0)
      setSellerId('')
    } catch (err) {
      console.error('save product error: ', err)
    } finally {
      setRequestStatus('idle')
    }
  }
}

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

Задание 1

Откройте ваше приложение со студентами. Откройте в нем файл NewStudentForm.jsx. Добавьте еще один локальный стейт requestStatus, и установите его изначально в 'idle'. Ознакомившись с материалами урока, заведите переменную canBeSaved, с помощью которой кнопка сохранения новых данных студента будет работать/не работать, в зависимости от значения requestStatus и от заполненности полей.

Задание 2

Напишите асинхронный код для onSaveStudentClick, который будет менять значение requestStatus по ситуации, отправлять thunk addProduct с данными нового студента, очищать поля в случае успешного запроса и выводить в консоль ошибку в случае неудачи, как показано в уроке. Используйте для этого конструкцию try-catch и функцию RTK unwrap.

Задание 3

Запустите ваше приложение, добавьте нового студента и убедитесь, что все работает.