React+Redux: ajout slides Redux Saga

This commit is contained in:
wpetit 2020-02-17 13:53:20 +01:00
parent 4aab1733df
commit 93f78ff5d5
2 changed files with 157 additions and 11 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@ -1,3 +1,8 @@
---
marp: true
---
<style> <style>
pre { font-size: 0.5em !important; } pre { font-size: 0.5em !important; }
table { font-size: 0.6em !important; } table { font-size: 0.6em !important; }
@ -401,6 +406,8 @@ export default class Clock extends React.Component {
Les événements du DOM sont interceptés par le passage de "callbacks" sur les propriétés `on<Event>` des composants. Les événements du DOM sont interceptés par le passage de "callbacks" sur les propriétés `on<Event>` des composants.
---
```jsx ```jsx
// my-app/src/components/counter.js // my-app/src/components/counter.js
@ -531,8 +538,8 @@ https://reactjs.org/docs/react-component.html
### Séquence de montage ### Séquence de montage
1. `constructor(props)` 1. `constructor(nextProps, currentState)`
2. `componentWillMount()` 2. `static getDerivedStateFromProps(nextProps, currentState)`
3. `render()` 3. `render()`
4. `componentDidMount()` 4. `componentDidMount()`
@ -540,11 +547,11 @@ https://reactjs.org/docs/react-component.html
### Séquence de mise à jour ### Séquence de mise à jour
1. `componentWillReceiveProps(nextProps)` 1. `static getDerivedStateFromProps(nextProps, currentState)`
2. `shouldComponentUpdate(nextProps, nextState)` 2. `shouldComponentUpdate(nextProps, nextState)`
3. `componentWillUpdate(nextProps, nextState)` 3. `render()`
4. `render()` 4. `getSnapshotBeforeUpdate(prevProps, prevState)`
5. `componentDidUpdate(prevProps, prevState)` 5. `componentDidUpdate(prevProps, prevState, snapshot)`
--- ---
@ -838,9 +845,9 @@ https://redux.js.org/
--- ---
## Flot des données ![bg right:75% contain](./img/redux_flow.png?1)
![center 100%](./img/redux_flow.png?1) ## Flot des données
--- ---
@ -905,7 +912,7 @@ export default const rootReducer = (state, action) => {
--- ---
## Création du `store` ## Création du `store`
``` ```javascript
// store.js // store.js
import { createStore } from 'redux' import { createStore } from 'redux'
@ -921,9 +928,8 @@ export function configureStore(initialState = { products: [] }) {
--- ---
## Tester ## Tester
``` ```js
// store.test.js // store.test.js
/* globals test, expect, jest */ /* globals test, expect, jest */
import { addProduct, removeProduct } from './actions' import { addProduct, removeProduct } from './actions'
import { configureStore } from './store' import { configureStore } from './store'
@ -1099,6 +1105,146 @@ export default connect(mapStateToProps)(App)
--- ---
## Redux-Saga
ou comment gérer les **"effets de bord"**
---
![bg right:75% contain](./img/reduxsaga_flow.png?1)
## Flot des données
---
### Cas d'usage
React-Redux permet d'intégrer au sein du "flux de travail" Redux la gestion des opérations asynchrones.
**Exemple** _Appels à des API distantes, opérations liées au passage du temps, messages websockets..._
Notamment, il offre une gestion de la **synchronisation d'opérations asynchrones** i.e. je dois attendre que l'opération A et l'opération B soient terminées pour effectuer l'opération C.
---
### Installation de la dépendance
```bash
npm install --save redux-saga
```
---
### Ajout du middleware
```js
// src/store/store.js
import { createStore, applyMiddleware, combineReducers, compose } from 'redux'
import myReducer from '../reducers/my'
import rootSaga from '../sagas/root'
import createSagaMiddleware from 'redux-saga'
const sagaMiddleware = createSagaMiddleware()
const rootReducer = combineReducers({
my: myReducer,
});
export function configureStore(initialState = {}) {
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(sagaMiddleware)
)
)
sagaMiddleware.run(rootSaga);
return store;
}
```
---
## Création de la saga "racine"
_Avec une saga "factice" d'authentification_
```js
// src/sagas/root.js
import { all, takeLatest } from 'redux-saga/effects';
import { LOGIN_REQUEST } from '../actions/auth';
import { loginSaga } from './auth';
export default function* rootSaga() {
yield all([
takeLatest(LOGIN_REQUEST, loginSaga),
]);
}
```
---
## Définition des actions
```js
// src/actions/auth.js
export const LOGIN_REQUEST = 'LOGIN_REQUEST'
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
export const LOGIN_FAILURE = 'LOGIN_FAILURE';
export function login(username, password) {
return { type: LOGIN_REQUEST, username, password }
}
export function loginFailure(username, error) {
return { type: LOGIN_FAILURE, username, error }
}
export function loginSuccess(username) {
return { type: LOGIN_SUCCESS, username }
}
```
---
## Création de ma saga d'authentification
```js
// src/sagas/auth.js
import { call, put } from 'redux-saga/effects';
import { loginFailure, loginSuccess } from '../actions/auth';
export default function* loginSaga(action) {
let result;
try {
result = yield call(doLogin, action.username, action.password);
} catch(err) {
yield put(loginFailure(action.username, err));
}
if ('error' in result) {
yield put(loginFailure(action.username, result.error));
return
}
yield put(loginSuccess(action.username));
}
function doLogin(username, password) {
return fetch('http://my-backend.org/login', {
method: 'POST',
body: JSON.stringify({
Username: username,
Password: password
}),
mode: 'cors',
credentials: 'include'
}).then(res => res.json())
}
```
---
## Mise en application ## Mise en application
--- ---