Дополнительные редьюсеры в 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
при запросе
данных, как показано в уроке.