}
```
```typescript
render() {
return
}
```
Sinon une CSS globale, ou une CSS par composant (Webpack powered)
```typescript
const css = require('./mycomponent.css');
```
---
#React-bootstrap
Adaptation des composants bootstrap à React
```typescript
```
La documentation
* [https://react-bootstrap.github.io/components.html](https://react-bootstrap.github.io/components.html)
* [http://getbootstrap.com/components/](http://getbootstrap.com/components/)
---
# Rappels
* Un composant a des propriétés et des états
* Un composant stateless est plus maintenable et testable
* On ne peut passer des propriétés qu'aux enfants (ce n'est pas de l'héritage;) )
---
layout: false
class: center, middle, inverse
# Flux & Redux
---
template: default
layout: true
### Flux & Redux
---
# Flux
Comment passer des informations aux petits enfants ?
![why redux diagram](./whyredux.png)
---
# Flux
Comment passer des informations aux petits enfants ?
![why redux diagram](./whyredux2.png)
---
# How To
![best practices](./flux-bestpractice.png)
* On ne met pas à jour directement les autres composants
* On passe par le store (redux), les stores (flux), les observables (RxJs), ...
---
# Flux
* Store: Stocker la donnée + Logique
* Action: Modifier le modèle
* Dispatcher: Répartir les actions dans les stores
* View: Les composants UI
![flux acton diagram](./flux.png)
**Le flux ne va que dans un seul sens !** (~~2-way binding~~)
---
# Redux
* Un store unique (pratique pour l'isomorphisme)
* L'état du store est read-only
* On émet des *actions* pour modifier l'état
* Les actions sont interprétées par des *reducers*
* les *reducers* sont des fonctions *pures*
* les *reducers* prennent en entrée l'état précédent et une action
* ils retournent le nouvel état dans un objet immutable
![redux](redux.png)
---
# Actions
### Actions
```typescript
{type: 'INCREMENT', inc: 3}
{type: 'ADD_TODO', text: 'Acheter du pain'}
{type: 'SET_USER', user: new User(1, 'toto')}
```
### Interface
```typescript
export interface CounterAction {
type: string;
inc: number;
}
```
### Action Creator
```typescript
export const incrementor = (inc: number): CounterAction => {
return {type: 'INCREMENT', inc: inc};
};
```
![redux](redux.png)
---
# Reducer
```typescript
export const display =
(state: number = 0, action: CounterAction) => {
switch (action.type) {
case 'INCREMENT':
return state + action.inc;
case 'DECREMENT':
return state - action.inc;
default:
return state;
}
};
```
Le *state* est non mutable !
![redux](./redux.png)
---
# Store
```typescript
interface Store {
dispatch: Dispatch;
getState(): S;
subscribe(listener: () => void): Unsubscribe;
replaceReducer(nextReducer: Reducer): void;
}
```
* Le *store* garde l'état de l'application. On y accède via *getState()*.
* ~~setState()~~ !! On modifie l'état en 'dispatchant' une action: *dispatch(filterWarnings(true))*
* On peut être prévenu des changements du store via *subscribe(listener)*
* On se désenregistre avec la méthode retournée par *subscribe*
![redux](./redux.png)
---
layout: false
class: center, middle, inverse
# React & Redux
---
template: default
layout: true
### React & Redux
---
# Récapitulatif
- Actions
- Reducers
- Store
- Composants React
- Il reste à lier les composants au store !
![redux](./redux.png)
---
# Présentation et Conteneur
* Les composants stateless sont simples à maintenir
* Séparation des responsabilités
![react-redux](./conteneur-pres.png)
---
# Présentation et Conteneur
** On découpe nos composants (connectés au *store*) en 2, *présentation* & *conteneur* **
| | Presentational Components | Container Components |
| ------------- |-----------------------------------| ----------------------------------------------|
| Purpose |How things look (markup, styles) | How things work (data fetching, state updates)|
| Aware of Redux| No | Yes |
| To read data | Read data from props | Subscribe to Redux state |
| To change data| Invoke callbacks from props | Dispatch Redux actions |
| Are written | By hand | Usually generated by React Redux |
---
template: default
layout: true
### Actions asynchrones
---
# Généralités
* Redux ne permet que de dispatcher des objets
* **redux-thunk** permet de passer une fonction, et donc des actions asynchrones ou des actions avec conditions.
C'est un **middleware**.
* C'est plus élégant que les actions retournent des **promesses**
---
# ThunkAction
Une **ThunkAction** est une fonction qui reçoit en entrée les méthodes *dispatch()* et *getState()*, et retourne le
résultat de **dispatch()**.
Dans le code, on va écrire des **ThunkActionCreator**.
```typescript
export const fetchItems: ThunkActionCreator = () =>
(dispatch, getState) => getItems(getState().userId)
.then(items => {
dispatch(setItems(items));
})
.catch((error: any) => {
console.log(error);
});
```
---
template: default
layout: true
### Context
---
# Mises en garde
* On peut passer des objets à ses composants enfants (n'importe où dans la hiérarchie).
* Des librairies sont basées la dessus, mais ce n'est pas officiellement supporté (le fonctionnement pourra varier, être supprimé).
La doc par d'**experimental API** !
* *react-redux* fonctionne grâce à ca (le store est passé à tous les enfants).
* ** A n'utiliser qu'en cas d'urgence ;)**
---
template: default
layout: true
### Tests
---
# Jest & Enzyme
L'idée est de tester les composants de *présentation*, avec leurs états et leurs propriétés.
[Jest API](https://facebook.github.io/jest/docs/api.html#content)
[Enzyme API](https://github.com/airbnb/enzyme/blob/master/docs/api/shallow.md)
```typescript
import React from 'react';
import {shallow} from 'enzyme';
describe(MyComponent, () => {
it('should work !', () => {
const component = shallow();
});
});
```
---
# Quelques exemples
Vérifier que le composant s'affiche avec ses sous composants
```typescript
describe(MyComponent, () => {
it('renders MyComponent and its sub components', () => {
const component = shallow(
);
expect(component.find(SubComponent1).exists()).toBeTruthy();
expect(component.find(SubComponent2).exists()).toBeTruthy();
});
});
```
Vérifier le texte du composant
```typescript
expect(component.text()).toContain('mon texte attendu');
```
Vérifier qu'une méthode a été appelée
```typescript
const mockOnChange = jest.fn();
expect(mockOnChange).toBeCalledWith(myParam);
```
---
# Quelques exemples
Simuler un événement
```typescript
component.find('button').at(1).simulate('click');
component.find('input').simulate('change', {target: {value: 'ma valeur'}});
```
Appeler une méthode
```typescript
component.instance().maMethode();
```
Récupérer l'état
```typescript
expect(component.state('name')).toEqual('mon nom');
```
---
class: center, middle, inverse
layout: false
# La suite
---
template: default
layout: true
### La suite... en formation :)
---
# Librairies, outils, features
- Le routing (react-router)
- Injection de dépendances
- Isomorphisme
- après redux (saga, mobx, redux-rs, ...)
- les outils (debugging, performances, ...)
---
class: center, middle, inverse
layout: false
# Des questions ?
#### [codox.fr](http://codox.fr)