#CestFacile : Redux Saga

Toujours dans la lignée de cette série d’articles pour démonter à quel point « c’est facile » de rentrer dans ce monde joyeux de React, voici un petit guide pour implémenter Redux Saga au sein d’un projet create-react-app.

J’en ai déjà parlé

J’ai déjà fait un post à ce sujet il y a quelques mois, vous pouvez le retrouver ici pour plus d’infos sur l’intérêt d’utiliser cette librairie, mais en deux mots, l’idée autour de Redux Saga – tout comme Redux Thunk, est de permettre d’éviter les « side-effects » qui sont le meilleur ennemi d’un développeur qui veut rester dans l’approche de la programmation fonctionnelle.

Redux nécessite d’utiliser des fonctions pures, et c’est précision un soucis lorsque vous commencer à travailler avec des APIs ou plus globalement tout ce qui n’est potentiellement pas synchrone dans une application front.

Implémentons

Si vous partez d’un projet from scratch, vous pouvez jeter un oeil à mon précédent article qui vous permettra de mettre en place Redux en quelques minutes. On reprend précisément là où on s’était arrêté dans cet article.

On commence par un petit coup de yarn :

yarn add redux-saga

On va maintenant modifier notre configureStore :

import {createStore, applyMiddleware} from 'redux'
import createSagaMiddleWare from 'redux-saga'
import rootReducer from './rootReducer'
import Sagas from '../Services/Sagas'

const sagaMiddleware = createSagaMiddleWare();
const configureStore = () => {
  const store = createStore(rootReducer, applyMiddleware(sagaMiddleware))
  sagaMiddleware.run(Sagas)
  return store;
}

export default configureStore;

Dans Store/configureStore.js

On créé notre Root Sagas selon l’implémentation proposée ici et qui me semble avoir du sens.

import {fork} from 'redux-saga/effects'
import watchStuff from './Stuff/sagas'

const sagas = [
  watchStuff,
]

function* rootSaga() {
  yield sagas.map(saga=>fork(saga));
}

export default rootSaga

Dans Services/Sagas.js

On créé notre première Saga pour notre service Stuff
import { call, put, takeEvery } from 'redux-saga/effects'
import {doSomething} from './actions'

const someAPICalls = {
  fetchDataFromWebservices(payload){
    return newPromise( (resolve, reject) => {
      setTimeout(resolve, 3000, 'Manger des briques')
    })
  }
}

function* fetchSomething(action){
  const payload = yield call(someAPICalls.fetchDataFromWebservices, action.payload)
  yield put(doSomething(payload))
}

function* watchStuff(){
  yield takeEvery('DO_SOMETHING_ASYNC', fetchSomething)
}
export default watchStuff;

Dans Services/Stuff/sagas.js

Un peu d’explications :
– Pour illustrer le côté async, je renvoie une promise avec un timeout de 3 secondes. Ca permet de simuler un appel à une API
– On déclare un générator watchStuff qui prend chaque action DO_SOMETHING_ASYNC et qui envoi ça à un autre generator, fetchSomething.
– fetchSomething envoi en bout de course un put, qui est tout simplement une action qu’on importe
On n’oubliera pas d’ajouter l’actionType qui va bien :
export const DO_SOMETHING_ASYNC = 'DO_SOMETHING_ASYNC'
Dans Services/Stuff/actionTypes
Et de créer une action :
export const doSomethingAsync = (payload) => ({
  type: types.DO_SOMETHING_ASYNC,
  payload
})

Dans Services/Stuff/actions.js

Maintenant on a plus qu’à dispatch cette action depuis App.js, par exemple au componentDidMount :
this.props.actions.doSomethingAsync({foo: 'bar'})
Au bout de 3 secondes, vous devriez voir apparaitre un nouvel élément dans la liste (après « lol »)

 

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *