Redux-saga jest biblioteką, która pozwala w prosty sposób zarządzać asynchronicznymi zapytaniami w naszej aplikacji. Opiera się ona na generatorach, które są nowością dostępną w ES6 czyli na specjalnych funkcjach które mogą być pauzowane i wznawiane. Do samych generatorów wrócę w osobnym wpisie ponieważ jest to dosyć ciekawy temat a póki co tyle wystarczy.

Konfiguracja Redux-saga

Zanim przejdę do właściwej implementacji powiem parę słów o właściwej konfiguracji tej biblioteki. Wszystko zaczyna się od zainstalowania jej poniższym poleceniem

yarn add redux-saga

To teraz można przejść do właściwego etapu konfiguracji. Redux-saga jest to Reduxowy middleware tzn.: wykonuje się pomiędzy wywołaniem akcji a jej obsłużeniem w związku z czym należy go zarejestrować podczas tworzenia Stora.

import createSagaMiddleware from 'redux-saga'

const sagaMiddleware = createSagaMiddleware()

let store = createStore(
  reducers,
  {},
  applyMiddleware(sagaMiddleware),
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
  );

sagaMiddleware.run(rootSaga)

Nie jest to ciężkie ale wymaga parę słów wyjaśnienia:

{} oznacza początkowy stan naszej aplikacji i musi być jawnie zdeklarowane podczas rejestracji middleware’ów

rootSaga jest zbiorem stworzonych przez nas generatorów w sadze, które chcemy by były obsługiwane. Aktualnie u mnie  wygląda to następująco:

export default function* rootSaga() {

  yield all([

    getEventsAsync(),

    addEventAsync()

  ])

}

Taka minimalna konfiguracja wystarczy żeby nasze generatory działały. No to teraz pytanie jak je pisać by działały?

Własne generatory w Redux-saga

Po prawidłowej konfiguracji zostało nam nic innego jak napisać funkcje tak by działały. Zacznę od tych, które są najwyżej czyli tych które przekazuję do rootSaga:

export function* getEventsAsync() {

    yield takeEvery('GET_EVENTS_ASYNC', getEvents)

}

Jest to dosyć prosta funkcja, która spełnia ważne zadanie. Za każdym razem gdy wywołamy akcję „GET_EVENTS_ASYNC” Redux-saga to zarejestruje i wywoła funkcję getEvents. Zamiast takeEvery możemy wykorzystać takeLatest, które zwróci dane z najnowszej(ostatniej) akcji.

function* getEvents() {
    try{
        const events = yield call(fetchGetEvents);
        yield put({ type: 'GET_EVENTS_SUCCESS', events:events  })
    }catch(e){
         yield put({ type: 'GET_EVENTS_FAILURE', message:e.message  })
    }
}

Tutaj wykorzystuję dwie kolejne funkcje call i put. Pierwsza z nich pozwala na wykonanie asynchronicznego zapytania. Uzyte tutaj słówko kluczowe yield powoduje zatrzymanie naszego generatora w oczekiwaniu na dane pochodzące z asynchronicznego zapytania. Jeśli się powiedzie to przy pomocy put tworzymy nową akcje i przekazujemy dane, które chcemy by były obsłużone. W tym momencie możemy użyć zwykłego reducera, który zaktualizuje nasz widok.

 

Jak widać Redux-saga jest dosyć prostą ale potężną biblioteką. Daje nam mnóstwo swobody przy jednoczesnym zachowaniu cyklu życia i aktualizacji aplikacji w reduxie. Możemy dzięki niej pobrać dane i zaktualizować widok w kilku miejscach jednocześnie dzięki czemu nie jesteśmy ograniczeni przy tworzeniu. Biblioteka dostaje dużego plusa ode mnie i pewnie będę ją stosować w innych projektach.