React+Redux: ajout slides Redux Saga
This commit is contained in:
parent
4aab1733df
commit
93f78ff5d5
Binary file not shown.
After Width: | Height: | Size: 68 KiB |
|
@ -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
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
Loading…
Reference in New Issue