Vous êtes sur la page 1sur 90

SEMAINE INTENSIVE REACT

Février 2020 | HETIC


Belle Epoque
➔ Agence spécialisée en développement
➔ Nous sommes ici car on utilise React au quotidien
➔ Hetic P2013 - P2019

Vous pouvez nous contacter


et postuler hello@agence-belle-epoque.fr

https://www.welcometothejungle.com/fr/companies/agence-belle-epoque/jobs

2
Déroulement

▫ Théorie + pratique
▫ Démos et exercices pour du concret
▫ Interaction / poser des questions
▫ Aidez-vous

3
Plan

▫ Pourquoi React
▫ Rappel ES6
▫ Installation
▫ Props & State
▫ React Lifecycle
▫ CSS
▫ React Router
▫ React avancé en fonction du temps : Redux, animations, SSR, tests…

4
Pourquoi
React
Commençons par la base
L’essentiel

▫ Facebook - Open source depuis 2013


▫ Librairie javascript pour créer des interfaces graphiques
▫ Rend des vues et répond à des événements
▫ Cible essentiellement des grosses applications JS avec des données qui changent
dans le temps

6
Quelques grands principes

▫ Approche composant
▫ Virtual DOM

7
La librairie Javascript la plus plébiscitée

Enquête annuelle réalisée par le site StackOverflow

https://2019.stateofjs.com/front-end-frameworks/

8
Les meilleurs
utilisent React

9
De sacrées possibilités

▫ React Native
▫ Progressive Web Apps
▫ React pour la VR
▫ React pour l’IoT

10
Une multitude de modules et d’outils

▫ Redux
▫ Reselect
▫ React Router
▫ Material UI
▫ Storybook
▫ Jest

11
Rappel ES6
Les bases

12
ES6 Pourquoi ?

▫ Plus facile
▫ Plus puissant
▫ Plus fiable
▫ Plus performant

13
Babel

Transpile ES6, ES7 en ES5 (lu par un browser)

14
Const ou Let :
telle est la question

➔ Donnez du sens à vos variables const maConstante = 'je ne change jamais';

let maVariable = 'je peux changer de valeur';


➔ N’utilisez plus le mot-clé “var”
maVariable = 'comme ceci';

15
Littéraux
➔ Simple quote ‘pour simple texte’ const maConstante = 'deux';
console.log(`ligne de texte 1
➔ Double quote avec attr=”Attribut” de ligne de texte ${maConstante}`);
balise non dynamique
"ligne de texte 1
➔ Backtick `avec des ${variables} et des ligne de texte deux"
textes sur plusieurs lignes`

16
The Spread Syntax

const mid = [3, 4]; const mid = [3, 4];


const arr = [1, 2, mid, 5, 6]; const arr = [1, 2, ...mid, 5, 6];

console.log(arr); console.log(arr);

[1, 2, [3, 4], 5, 6] [1, 2, 3, 4, 5, 6]

17
The Spread Syntax Object

const defaults = { first: 'John', last: 'Doe', age: 42 };


let trainer = { last: 'Smith', age: 35 };
trainer = { ...defaults, ...trainer, age: 36 };

// => { fist: 'John', last: 'Smith', age: 36 };

React :
<TodoItem key={todo.id} todo={todo} {...trainer} />

18
Destructuring

function printBasicInfo({firstName, secondName, profession}) {


console.log('variable access', {firstName, secondName, profession});
}

var person = {
firstName: 'John',
secondName: 'Smith',
age: 33,
children: 3,
profession: 'teacher'
}

printBasicInfo(person); 19
Destructuring 2

const { filter: selectedFilter, onShow } = this.props;

Const onShow = this.props.onShow;


Const selectedFilter = this.props.filter;

20
Arrow function

const getStuffAwesome = ({ id, name, force, verbose }) => {


...do stuff
}

Mot-clé “this” devient accessible sans binder

<TodoTextInput text={todo.text}
editing={(text) => this.handleSave(todo.id, text)} />

21
Classes

class TodoItem extends Component { render() {


constructor(props, context) { return (
super(props, context); <div onClick={(e) =>
this.state = { this.handleClick(e)}>
editing: false {this.state.editing &&
}; <p>Editing est à true</p>
} }
{!this.state.editing &&
handleClick(e) { <p>Editing est à false</p>
this.setState({ editing: true }); }
} </div>
);
}
} 22
Async / Await

- Créer une fonction asynchrone grâce au mot-clé “async”

- Attendre une réponse grâce au mot-clé “await”

- Faire moins de Callbacks et de Promesses


- Une compréhension plus simple des appels : fonction avec un aspect procédurale

23
Export / Import
// Import intégral dans une "namespace"
export function addTodo () {
import * as types from
return { type: types.ADD_TODO,
'../constants/ActionsTypes';
text }
}
// Ou juste un des deux modes :
import Footer from './Footer;
export const ADD_TODO =
import { ADD_TODO } from
'ADD_TODO';
'../contants/TodoFilters';
export default Footer;

24
Async / Await
function sendEmails(query) { async function sendEmails(query) {
const usersP = getUsers(query); const users = await getUsers(query);
// On récupère le champ "email" de tous les const emails = users.map(u => u.email);
utilisateurs const sentP = emails.map(email =>
const emailsP = usersP.then(users => sendMail(email, "Bonne fête"));
users.map(u => u.email)); return await Promise.all(sentP);
// Pour chaque email… }
const sentP = emailsP.then(emails =>
emails.map(email => { async function main() {
// … on envoie un mail try {
return sendMail(email, "Bonne fête"); await sendEmails({ firstName:
}) "Edouard" });
); console.log("OK");
// On attend que tous les envois soient } catch (e) {
résolus console.error("FAIL");
return Promise.all(sentP); }
} }

sendEmails({ firstName: "Edouard" }) main();


.then(() => console.log("OK"))
.catch(() => console.error("FAIL")); 25
Installation
Passons au concret...

26
nvm > npm & node

https://github.com/nvm-sh/nvm

https://nodejs.org/en/

27
Create React App

Official. No setup. Minimal.


npx create-react-app my-app && cd my-app

npm install

npm start

28
Architecture

my-app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│ └── favicon.ico
│ └── index.html
│ └── manifest.json
└── src
└── App.css
└── App.js
└── App.test.js
└── index.css
└── index.js
└── logo.svg
└── registerServiceWorker.js

29
ESLint config

https://bitbucket.org/snippets/lebrenn/8eara8
https://www.npmjs.com/package/eslint-config-prettier

30
Props & State

31
Props & state
handleClick(e) {
this.props : contient toutes les propriétés e.preventDefault();
disponibles d’un composant. Elles sont this.setState({ monEtat1: 'Nouvelle valeur' });
}
modifiables par le composant parent
render() {
this.state : contient tous les états return (
disponibles d’un composant. Ils peuvent <button onClick={(e) => this.handleClick(e)}>
changer au sein du composant <MonComposantEnfant
maProp1={this.state.monEtat1} />
</button>
);
}

32
Using State Correctly

// Wrong
this.state.comment = 'Hello';

// Correct
this.setState({comment: 'Hello'});

// Correct
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
33
Demo

Création de notre premier module : “compteur de clic”

1. Créer un nouveau composant de class


2. Définir un constructeur (état initial de notre composant)
3. Ajouter une fonction de rendu avec un bouton
4. Ajouter une action qui sera appelée à chaque clic sur le bouton et qui
incrémentera la valeur de notre compteur

34
Exercice

Créer une calculatrice simple avec les opérateurs


de bases :
+ - * /

35
CSS avec React
Qu’est ce qui change

36
CSS

Vous pouvez utiliser une feuille de style classique

Ou utiliser styled-component

37
Un peu de design

On va se faciliter la vie avec material UI

npm install --save material-ui

Il existe une multitude d’autres libraries

38
React Lifecycle

39
Les méthodes

React fournit des méthodes qui sont appelées pendant le cycle de vie d’un composant

▫ Permet de mettre à jour l’UI et l’état de l’application

40
Component Lifecycle

http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

41
render()

class Clock extends React.Component {


constructor(props) {
super(props);
this.state = { date: new Date() };
}

render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
} 42
componentDidMount()

componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}

43
componentWillUnmount()

componentWillUnmount() {
clearInterval(this.timerID);
}

44
// when the component is removed from the DOM...
componentWillUnmount() {
window.removeEventListener("resize", () =>
Longueur / Largeur this.onResizeHandler());
}

onResizeHandler() {
constructor(props) { const w = document.documentElement.clientWidth;
super(props); const h =
this.state = { document.documentElement.clientHeight;
w: null, console.log("The window has been resized!", {
h: null w,
}; h
} });
this.setState({ w, h });
componentWillMount() { }
// Force to get first document size.
this.onResizeHandler(); render() {
} const { w, h } = this.state;
return (
// when the component is added to the DOM... <ul>
componentDidMount() { <li>Width: {w}</li>
window.addEventListener("resize", () => <li>Height: {h}</li>
this.onResizeHandler()); </ul>
} ); 45
}
Exercice

Créer une TodoList avec :


- 1 formulaire d’ajout de tâche dont le champ se
vide une fois l’insertion effectuée
- 1 compteur de tâches
- 1 listing des tâches
- La possibilité de supprimer une tâche
- La possibilité de barrer une tâche au clic sur son
label
- La possibilité de supprimer l’ensemble des
tâches depuis le bouton “Reset task manager”

46
React Router

47
Installation

npm i react-router-dom --save

48
React Router Composant

Fournit des composants pour nous aider à construire l’architecture de nos pages

<BrowserRouter>, <Route>, <Link>

49
Afficher un <Router>

import { BrowserRouter } from 'react-router-dom'


ReactDOM.render((
<BrowserRouter>
<App />
</BrowserRouter>
), document.getElementById('root'))

50
L’<App>

Ce composant sera rendu par notre <Router>

const App = () => (


<div>
<Header />
<Main />
</div>
)

51
Routes

Le composant <Route> est le bloc de construction principal de React Router

const App = () => (


<div>
<Header />
<Route />
</div>
)

52
Path

Une <Route> attend une chaîne prop path qui décrit le type de chemin correspondant à l'itinéraire

Exemple :

<Route path='/roster'/ component={Roster} />

doit correspondre à un chemin commençant par / roster

53
Links

React Router dispose d’un composant <Link> pour faire des liens sans rechargement de page

import { Link } from 'react-router-dom'


const Header = () => (
<header>
<nav>
<ul>
<li><Link to='/'>Home</Link></li>
<li><Link to='/roster'>Roster</Link></li>
<li><Link to='/schedule'>Schedule</Link></li>
</ul>
</nav>
</header>
)
54
Route dynamique

<Route path="/single/:singleId" component={Single}/>

render() {
const singleId = this.props.routeParams.singleId;
}

55
Exercice

Créer un petit site simple avec une page d’accueil, une page blog avec des articles.
Lorsque l’on clique sur un article, on a la page single.

56
Tests unitaires

57
Pourquoi faire des tests unitaires

▫ Être plus productif (moins de temps passé à tester manuellement)


▫ Développer sans se soucier de tout casser
▫ Les tests peuvent servir de documentation pour comprendre un projet

58
Jest - Avantages

▫ Très rapide
▫ Snapshot
▫ “Watch mode” qui retourne seulement les tests qui sont pertinents pour vos
changements.
▫ Messages d’erreurs utiles
▫ Configuration simple
▫ Mocks et spies
▫ Coverage report with a single command line switch.

59
Redux

60
Dispatch

Plusieurs possibilités :
▫ Passer simplement la méthode au composant
▫ Créer un composant connecté

61
Dispatch : la méthode simple
// App.js
import { createStore } from 'redux';
import { MessageSending } from './MessageSending';
import reducer from './reducer';

const store = createStore(reducer);


class App extends React.Component {
render() {
<MessageSending store={store} />
};
};

// MessageSending.js
import { sendMessage } from './actions';
// ...
this.props.store.dispatch(sendMessage(message))
// ...
62
Le concept

63
Dispatch, la méthode recommandée

Le composant connecté

// MessageSendingConnected.js
import { connect } from 'react-redux';
import { sendMessage } from './actions';
import MessageSending from './MessageSending';

const mapDispatchToProps = {
sendMessage,
};

export default connect(null, mapDispatchToProps)


(MessageSending);
64
Actions

export const ADD_TODO = 'ADD_TODO';


export const ADD_PERSO_IN_LANDING = 'ADD_PERSO_IN_LANDING';

export function addTodo(text) {


return { type: ADD_TODO, text }
}

export const addPersoInLanding = (strateIndex, contents, paging, strates) =>


({
type: ADD_PERSO_IN_LANDING,
payload: {
strateIndex,
contents,
paging,
strates,
}, 65
});
Reducers

function todoApp(state = initialState, action) {


switch (action.type) {
case ADD_TODO:
return {
...state,
text: action.payload.text,
};
default:
return state
}
}

66
Store

import { combineReducers } from 'redux';


import { applicationReducer } from './../components/Application/Application-reducer';
import { pageReducer } from './../components/Page/Page-reducer';

const rootReducer = combineReducers({


application: applicationReducer,
page: pageReducer,
});

export default rootReducer;

const store = createStore(rootReducer, initialState);


67
View

import { connect } from 'react-redux';


import Page from './Page';

const mapStateToProps = (state) => {


const { page } = state;
const { displayTemplate, displayName } = page;

return {
displayTemplate,
displayName,
};
};
export default connect(mapStateToProps)(Page); 68
Exercice

Suite du précédent exercice, mettre en favoris des articles

69
Animations

70
L’UX et l’UI sont au coeur des applications

71
Avant de commencer

On a tous envie de mettre des animations partout

72
Mais ne surchargez pas votre app

Animez l’élément qui doit capter l’attention de l’utilisateur

73
Evitez les animations trop longues

300 ms est un bon compromis

74
Animation CSS basée sur les états de React

▫ Le plus simple
▫ Parfait pour des animations basiques
▫ Performant
▫ Ne surcharge pas

75
Exemple du Menu

76
Transition Group

npm install react-transition-group --save

Documentation : https://reactcommunity.org/react-transition-group/

77
Transition

▫ Permet de faire des transition lors d’un changement d’état


▫ API déclarative simple
▫ Ne modifie pas le comportement du composant rendu, il ne fait que suivre les
états "entrée" et "sortie" pour les composants.
▫ C’est à nous de donner un sens et un effet lors des changements

78
Transition

4 états principaux fournis :


▫ ENTERING
▫ ENTERED
▫ EXITING
▫ EXITED

Transition state est modifié par le in prop


➔ Quand il est à true il s’affiche

79
Transition

<Transition timeout={300} .fade {

in={this.state.enterAnimation}> opacity: 0;

{state => ( transition: opacity 300ms ease-in-out;

<div className={`fade fade-${state}`}> }

<h1>test</h1> .fade-entered {

</div> opacity: 1;

)} }

</Transition> .fade-entering {
opacity: 0;
}

80
Transition Group

▫ Gère un ensemble de composants


▫ On peut utiliser n'importe quel composant <Transition> ou <CSSTransition>
dans un <TransitionGroup>

81
CSS Transition

▫ Composant Transition utilisant CSS transitions et les animations.


▫ Inspiré par la librarie ng-animate Angular
▫ CSS Transition ajoute des classes au moment des états : appear, enter, exit

82
CSS Transition
<CSSTransition .fade-enter {
{...props} opacity: 0.01;
timeout={1000} }
classNames="fade"
> .fade-enter.fade-enter-active {
{children} opacity: 1;
</CSSTransition> transition: opacity 1000ms ease-in;
}

.fade-exit {
opacity: 1;
}

.fade-exit.fade-exit-active {
opacity: 0.01;
transition: opacity 800ms ease-in;
}

83
React Motion

▫ API pour faire des animations


▫ Permet de faire à peu près tout
▫ Fonctionne avec React Native
▫ Donne un cadre

84

For 95% of use-cases of animating components, we don't have to resort to using hard-
coded easing curves and duration.

Set up a stiffness and damping for your UI element, and let the magic of physics take
care of the rest.

This way, you don't have to worry about petty situations such as interrupted animation
behavior. It also greatly simplifies the API.

Cheng Lou

85
React Motion

<Motion defaultStyle={{ scaleX: 1 }} style={{ scaleX: spring(0) }}>

86
GSAP

▫ Fait tout
▫ Possibilité de régler la vitesse, le style de l’animation…
▫ Se couple parfaitement avec React Transition Group

87
Beaucoup d’autres librairies

▫ Velocity
▫ Animated
▫ ...

88
Exercice

89
Merci
Vous pouvez nous contacter et postuler
▫ hello@agence-belle-epoque.fr
▫ https://www.welcometothejungle.com/fr/companies/agence-belle-epoque/jobs

90

Vous aimerez peut-être aussi