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



Чат с GPT Компилятор