Дополнительные редьюсеры в Redux
Давайте откроем наше приложение с продуктами,
а в нем файл productsSlice.js. Наверное вы
заметили, что мы создавали thunk fetchProducts
как отдельную функцию? Мы сделали так, потому
что createSlice не поддерживает определение
thunks. Как же нам в этом случае заставить
reducer слайса products отвечать на экшены,
которые определены за пределами products?
Ведь нам как раз нужно обработать экшены,
которые посылает thunk fetchProducts.
Для таких случаев у createSlice есть
свойство extraReducers, которое позволяет
добавлять дополнительные редьюсеры, которые
в свою очередь и будут обрабатывать экшены,
определенные не в данном слайсе.
Давайте теперь в теле функции createSlice
после свойства reducers со всеми редьюсерами
добавим еще один метод extraReducers:
extraReducers() {},
Этому методу мы должны передать объект
builder, у которого есть методы, с
помощью которых можно добавить
дополнительные редьюсеры:
extraReducers(builder) {},
Мы будем использовать один из методов builder -
addCase, который первым параметром принимает
action creator, а вторым reducer. Один из
экшенов, который нам будет отправлять
fetchProducts при запросе это
fetchProducts.pending, что говорит нам
о том, что запрос отправлен. Давайте в этом
случае будем менять статус на 'in progress'
(до этого он был 'idle'):
extraReducers(builder) {
builder.addCase(fetchProducts.pending, (state) => {
state.status = 'in progress'
})
},
Теперь обработаем экшен, который отправится
в случае успешного запроса. Здесь мы будем
менять не только статус в стейте на
'success', но и заберем продукты в
слайс products из payload экшена.
Чтобы собрать все продукты нам понадобиться
метод concat:
extraReducers(builder) {
builder
.addCase(fetchProducts.pending, (state) => {
state.status = 'in progress'
})
.addCase(fetchProducts.fulfilled, (state, action) => {
state.status = 'success'
state.products = state.products.concat(action.payload)
})
},
В случае неудачного запроса мы поменяем
статус на 'fail' и запишем в стейт
сообщение об ошибке:
.addCase(fetchProducts.rejected, (state, action) => {
state.status = 'fail'
state.error = action.error.message
})
Если мы сейчас запустим наше приложение
и в меню кликнем по 'Products', то
через пару секунд (помните про задержку,
которую мы выставили на сервере?) увидим
список с продуктами.
Точно также мы увидим изменения и в Redux
DevTools. Теперь наши продукты появятся и
в стейте (посмотрите вкладку 'State'),
если вы кликнули по экшену
products/fetchProducts/fulfilled.
Там же появится и новый статус 'success'.
Кликните теперь на экшен
products/fetchProducts/pending и посмотрите,
чем теперь отличается вкладка 'State'.
Единственный неприятный момент, который
у вас может случиться (я говорил про это
на предыдущем уроке) - это дублирование
запроса данных. В результате чего, у нас
в списке получится не 8, а целых
16 продуктов и критические предупреждения
в консоли разработчика. Давайте
разберемся с этим на следующем уроке.
Откройте ваше приложение со студентами.
Откройте в нем файл studentsSlice.js. В
теле функции createSlice после свойства
reducers добавьте свойство extraReducers.
Передайте методу extraReducers builder.
С помощью метода builder.addCase
добавьте обработку для экшенов pending,
fulfilled и rejected, которые
отправляет fetchStudents при запросе
данных, как показано в уроке.