redux-thunk
W sekcji poświęconej akcjom i kreatorom akcji poznaliśmy kilka ograniczeń:
- kreatory akcji muszą być synchroniczne,
- kreatory akcji nie mają dostępu do stanu Reduxa
Oznacza to ,ze nie możemy używać kreatorów np. do pobrania danych z API i przekazania ich do Reduxa; wszelkie tego typu operacje musiały by mieć miejsce w cyklu życia komponentu. Nieco komplikuje to działanie Reduxa:
- Komponent rozpoczyna pobieranie danych
- Komponent przekazuje dane do akcji
- Akcja aktualizuje Redux
- Komponent dostaje dane jako props
Niestety, w ten sposób znów "wiążemy" nasz komponent UI z logiką aplikacji. Aby temu zapobiec możemy użyć middleware redux-thunk. Uzbrojeni w wiedzę nt. działania middleware zacznijmy od analizy kodu źródłowego:
const thunkMiddleware = ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState);
}
return next(action);
};
Kod został nieznacznie uproszczony na potrzeby przykładu.
Przykładowy thunk
Jak widać, middleware wykonuje tylko jedną prostą operację: jeżeli wartość przekazana do dispatch()
jest funkcją, zostaje ona przechwycona (nie jest wywołane next(action)
) i wywołana z 2 argumentami: dispatch
i getState
. Dzięki temu możemy tworzyć "thunki"
const getDataFromApi = () => {
// Nasz action creator nie zwraca akcji, ale funkcję
return function getData(dispatch) {
// Funkcja zostaje następnie wywołana przez redux-thunk i otrzymuje
// dostęp do dispatch i getStore. Wykonujemy zapytanie do API.
makeApiCall().then(data => {
// I kiedy zostanie ono zakończone, dispatchujemy właściwą akcję
dispatch({
type: 'DATA_LOADED',
payload: data
});
}).catch(error => {
dispatch({
type: 'DATA_LOAD_ERROR',
error: true,
payload: error
});
});
}
};
const mapDispatchToProps = {
getDataFromApi
};
W tym momencie przebieg danych jest następujący:
- Komponent wywołuje
props.getDataFromApi()
- Do Reduxa dispatchowana jest funkcja
getData
- Middleware
redux-thunk
sprawdza, że typemaction
jestfunction
; wywołuje funkcję z argumentemdispatch
igetState
(który ignorujemy) i przerywa łańcuch - Funkcja
getData
zostaje wywołana i wykonuje zapytanie do api (Promise) makeApiCall
wykonuje się poprawnie (lub z błędem) i wywołujedispatch
z właściwą akcją- Middleware
redux-thunk
sprawdz, że typemaction
NIE jestfunction
i po prostu przekazuje ją do kolejnego middleware i dalej reducera - Komponent ulega przerenderowaniu z nowymi danymi