Dodatkowe reducery w Redux
Otwórzmy naszą aplikację z produktami,
a w niej plik productsSlice.js. Prawdopodobnie
zauważyłeś, że tworzyliśmy thunka fetchProducts
jako oddzielną funkcję? Zrobiliśmy tak, ponieważ
createSlice nie obsługuje definiowania
thunków. Jak w takim razie sprawić, aby
reducer slice'a products reagował na akcje,
które są zdefiniowane poza products?
W końcu potrzebujemy przetworzyć akcje,
które wysyła thunk fetchProducts.
W takich przypadkach createSlice ma
właściwość extraReducers, która pozwala
dodawać dodatkowe reducery, które
z kolei będą przetwarzać akcje
zdefiniowane nie w tym slice'u.
Dodajmy teraz w ciele funkcji createSlice
po właściwości reducers ze wszystkimi reducerami
kolejną metodę extraReducers:
extraReducers() {},
Musimy przekazać jej obiekt
builder, który ma metody, za
pomocą których można dodać
dodatkowe reducery:
extraReducers(builder) {},
Będziemy używać jednej z metod builder -
addCase, która przyjmuje pierwszym parametrem
action creator, a drugim reducer. Jedna z
akcji, którą będzie nam wysyłać
fetchProducts przy żądaniu to
fetchProducts.pending, co mówi nam
o tym, że żądanie zostało wysłane. W tym
przypadku zmieńmy status na 'in progress'
(wcześniej był 'idle'):
extraReducers(builder) {
builder.addCase(fetchProducts.pending, (state) => {
state.status = 'in progress'
})
},
Teraz przetwórzmy akcję, która wyśle się
w przypadku udanego żądania. Tutaj będziemy
zmieniać nie tylko status w stanie na
'success', ale także zabierzemy produkty do
slice'a products z payload akcji.
Aby zebrać wszystkie produkty, przyda nam się
metoda 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)
})
},
W przypadku nieudanego żądania zmienimy
status na 'fail' i zapiszemy w stanie
komunikat o błędzie:
.addCase(fetchProducts.rejected, (state, action) => {
state.status = 'fail'
state.error = action.error.message
})
Jeśli teraz uruchomimy naszą aplikację
i w menu klikniemy na 'Products', to
po kilku sekundach (pamiętasz o opóźnieniu,
które ustawiliśmy na serwerze?) zobaczymy
listę z produktami.
Tak samo zobaczymy zmiany w Redux
DevTools. Teraz nasze produkty pojawią się i
w stanie (spójrz na zakładkę 'State'),
jeśli kliknąłeś na akcję
products/fetchProducts/fulfilled.
Pojawi się tam też nowy status 'success'.
Kliknij teraz na akcję
products/fetchProducts/pending i spójrz,
czym teraz różni się zakładka 'State'.
Jedyna nieprzyjemna rzecz, która
może ci się przytrafić (mówiłem o tym
na poprzedniej lekcji) - to duplikowanie
żądania danych. W wyniku czego, u nas
na liście otrzymamy nie 8, a całe
16 produktów i krytyczne ostrzeżenia
w konsoli deweloperskiej. Zajmijmy się
tym na następnej lekcji.
Otwórz twoją aplikację ze studentami.
Otwórz w niej plik studentsSlice.js. W
ciele funkcji createSlice po właściwości
reducers dodaj właściwość extraReducers.
Przekaż metodzie extraReducers builder.
Za pomocą metody builder.addCase
dodaj obsługę dla akcji pending,
fulfilled i rejected, które
wysyła fetchStudents przy żądaniu
danych, jak pokazano na lekcji.