1 of 191

Introduction au développement Web avec React JS

2025

2 of 191

Introduction

2025

3 of 191

Introduction - nombreux framework web

3

2025

4 of 191

Introduction - nombreux framework web

4

2025

5 of 191

Introduction - pourquoi React ?

Angular en perte de vitesse :

trop lourd et trop de breaking changes

React est l’un des framework web les

plus populaire et les plus apprécié des développeurs*

Communauté importante

Relativement simple et flexible

5

2025

6 of 191

Introduction - pourquoi React ?

6

2025

7 of 191

Introduction - qu’est-ce que React

Librairie JavaScript permettant la création de composants

Créée par Facebook

1ère version publiée en 2013 (actuellement en v19.2)

Utilisée par twitter, Instagram, WhatsApp, Netflix

https://github.com/facebook/react/blob/main/CHANGELOG.md

https://github.com/orgs/facebook/repositories?q=sort%3Astars

7

2025

8 of 191

Introduction - librairie

C’est une librairie et non un framework

Librairie : ensemble de fonctions qu’on peut appeler pour faciliter les développements. Ex : jQuery

Framework : structure définissant le fonctionnement de l’app et qui va venir appeler le code développé.

Ex : Angular

8

2025

9 of 191

Introduction - librairie

Avantages de la librairie :

  • Peut être intégré sur un site web existant sans tout refaire
  • Peut fonctionner avec d’autres librairies ou avec un framework

=> Très intéressant pour refondre progressivement un site web

9

2025

10 of 191

Introduction - librairie … framework

La version 19 de React introduit les “Server Components” et les “Server Functions” visant à créer un écosystème fullstack.

La documentation officielle incite de plus en plus à utiliser des framework basés sur React, tels que Next.js ou React Router afin de profiter de toutes les fonctionnalités.

Problème : amène un couplage fort entre le front et le back

10

2025

11 of 191

Introduction - React Native

React Native est un framework permettant de développer des applications mobiles : Android, iOS

Encapsule les composants natifs pour être manipulés en React et Javascript

Plus performant et mieux intégré que l’approche hybride d’autres frameworks comme Cordova qui encapsulent une application Web

11

2025

12 of 191

Introduction - React Native

… Mais nous ne nous intéresserons dans ce cours qu’à la librairie React pour le développement d’applications Web

12

2025

13 of 191

SPA, DOM & composants

2025

14 of 191

SPA – Single Page Application

SPA : une application web dynamique accessible via une page web unique

Plus fluide et réactif car permet d’éviter le chargement d’une nouvelle page à chaque action de l’utilisateur

14

2025

15 of 191

SPA – Single Page Application

Contrairement à un site web classique, une SPA est composée d’une seule page.

Le rôle du browser (front-end) est beaucoup plus important : toute la logique applicative y est déportée.

Le serveur (back-end) est "seulement" responsable de la fourniture des ressources à l’application et surtout de l'exposition des données.

15

2025

16 of 191

SPA – Single Page Application

Faire attention :

  • à la taille du DOM
  • aux traitements longs
  • à l’empreinte mémoire de l'application

Risques : applications longues à charger (page blanche ou partiellement chargée), site qui lag ou freeze

16

2025

17 of 191

SPA – Single Page Application

Solutions :

  • Ne charger que les éléments nécessaires
  • Ecrire et tester correctement son code
  • Utiliser une solution basée sur un "virtual DOM" (comme React)
  • Utiliser un framework quand nécessaire -> éviter pour les landing page ou sites statiques

17

2025

18 of 191

DOM - Document Object Model

Représentation objet d’une page Web

Implémentation gérée par les navigateurs

Permet des manipulations via JavaScript et CSS.

18

2025

19 of 191

DOM - Document Object Model

Problème : la modification du DOM est lente

Le DOM n’est pas conçu pour des modifications dynamiques et désordonnées

Chaque modification de la structure du HTML oblige le navigateur internet à recalculer tous les styles et le rendu de la page.

19

2025

20 of 191

DOM - Document Object Model

Solution n°1 : le Shadow DOM

  • c’est un morceaux de DOM qui a son propre style
  • les shadow DOM sont référencés dans le DOM principal ou dans d’autres shadow DOM
  • permet de limiter les calculs de rendu à chaque modification de la page
  • standardisé par le W3C

20

2025

21 of 191

DOM - Document Object Model

Solution n°2 : le Virtual DOM

  • copie du DOM optimisée pour la modification
  • permet une mise à jour efficace du “vrai” DOM :
    • mise à jour par lots
    • seuls les éléments modifiés sont mis à jour

  • solution utilisée par React

21

2025

22 of 191

DOM - Document Object Model

22

2025

23 of 191

Composants

Approche composant -> découper la page Web en modules les plus petit possible

Chaque composant a :

  • des données : son état
  • une vue : affichage, rendu
  • fonctions : comportement, actions possibles

Ex checkbox : (dé)cochée, ☑, sélection donnée associée

23

2025

24 of 191

Composants

Avantages :

  • facilité d’usage
  • réutilisabilité
  • partage et limitation des responsabilités
  • testables (unitairement et fonctionnellement)
  • maintenables et évolutifs

24

2025

25 of 191

Composants - design system

A grande échelle, conception d’une bibliothèque de composants intégrée à un design system (ensemble des éléments graphique définissant l’identité de la marque)

Plusieurs niveaux de composant : atomes, molécules, organisms, templates.

Ex : Decathlon avec l’utilisation de Storybook

25

2025

26 of 191

Composants

Et React dans tout ça ?

React facilite la création de composants en synchronisant automatiquement l’affichage avec l’état.

26

2025

27 of 191

Mon 1er composant

2025

28 of 191

1er composant - Choisir un IDE

Webstorm ou IDEA (licences étudiant)

Visual Studio

N’importe quel éditeur de texte (vi, emacs, ...)

IDE en ligne pour tester au fil du cours (https://codesandbox.io/ ou autre)

28

2025

29 of 191

1er composant - installer node et npm

Node.JS : JavaScript runtime

Permet d’exécuter des scripts / applications

JavaScript hors du navigateur.

npm : Node Package Manager

Permet à la fois de télécharger des applications node et de gérer les dépendances de ses projets

Possibilité d’utiliser d’autres gestionnaires de dépendances tels que Yarn ou pnpm

29

2025

30 of 191

1er composant - installer node et npm

30

2025

31 of 191

1er composant - création de l’app

create-react-app - déprécié

Alternative en TypeScript :

💡Possible de créer ses propres templates

31

2025

(sudo) npm install -g create-react-app

npx create-react-app my-app

cd my-app

npm start

npx create-react-app my-app --template typescript

32 of 191

1er composant - création de l’app

Vite

Avant de devenir l’outil de build officiel de React, Vite a été initialement conçu pour Vue.js

32

2025

npm create vite@latest my-app -- --template react-ts

33 of 191

33

2025

34 of 191

1er composant - le projet

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

└── serviceWorker.js

└── setupTests.js

34

2025

35 of 191

1er composant - ce qui a été généré

index.html : page d'accueil

35

2025

<noscript>You need to enable JavaScript to run this app.</noscript>

<div id="root"></div>

36 of 191

1er composant - ce qui a été généré

index.js : injecte le composant App dans la div “root”

36

2025

createRoot(document.getElementById('root')!)

.render(

<React.StrictMode>

<App />

</React.StrictMode>,

);

Le “!” sert à forcer la non-nullité pour TypeScript

37 of 191

1er composant - enfin

App.js

37

2025

function App() {

return (

<div className="App">

<header className="App-header">

<img src={logo} className="App-logo" alt="logo" />

<p> Edit <code>src/App.js</code> and save to reload. </p>

<a className="App-link" href="https://reactjs.org" target="_blank"

rel="noopener noreferrer">Learn React</a>

</header>

</div>

);

}

38 of 191

1er composant - compilation

Si j’essaie d’ouvrir directement le fichier index.html dans le navigateur, ça ne marche pas. 🤔

Les navigateurs n’interprètent pas nativement les composants React, il faut compiler l’application

Le site est généré dans le

dossier “build”

38

2025

npm run build

yarn build

39 of 191

1er composant - compilation

Transpileur (ou transcompilateur) Babel

source -> source (JavaScript)

Permet de définir les éléments du DOM en JSX

Permet d’utiliser de l’ES6 voir divers autres langages de programmation plutôt que du JavaScript : TypeScript, Reason, Kotlin

39

2025

40 of 191

JavaScript vs TypeScript

TypeScript est en sur-ensemble de JavaScript développé par Microsoft (en open source).

Spécification ES6 + typage statique des variables et fonctions et définition d’interfaces.

Contraignant, mais apporte de la sécurité en évitant beaucoup d’erreurs à l’exécution ; et permet l’autocomplétion des IDEs

=> TypeScript préférable pour les gros projets

40

2025

🍌

41 of 191

1er composant - publication

Commiter ses sources sur Git (Github, GitLab, Bitbucket)

Brancher le repos sur https://vercel.com/ pour builder et déployer automatiquement l’application à chaque commit

https://ubo-react-demo.vercel.app

https://urc.vercel.app

https://esport-ubo.vercel.app

41

2025

42 of 191

Les dépendances

2025

43 of 191

Les dépendances

Le fichier package.json permet de configurer son projet et de lister les dépendances

43

2025

"dependencies": {

"cra-template": "1.0.3",

"react": "^16.13.1",

"react-dom": "^16.13.1",

"react-scripts": "3.4.3"

}

44 of 191

Les dépendances

Version : [major].[minor].[patch]

Les versions peuvent être :

  • fixes : "librairie": "1.0.3"
  • en comparaison : "librairie": ">=1.0.3"
  • approximatives : "librairie": "~1.0.3"

Autorise les versions patch supérieures ou les versions mineures si seul le major est spécifié

  • équivalentes : "librairie": "^1.0.3"

Autorise les màj qui ne modifient pas le digit non nul le plus à gauche

44

2025

45 of 191

Les dépendances

Exemple : ajout de 2 dépendances @material pour pouvoir utiliser les composants material-ui

45

2025

"dependencies": {

"cra-template": "1.0.3",

"react": "^16.13.1",

"react-dom": "^16.13.1",

"react-scripts": "3.4.3",

"@material-ui/core": "4.11.0",

"@material-ui/icons": "4.9.1"

}

46 of 191

Les dépendances

Plutôt que de modifier directement le fichier package.json, il est également possible d’ajouter des dépendances via npm

46

2025

npm install --save react-router-dom

47 of 191

Les dépendances

On n’a plus qu’à importer les composants et les ajouter dans le rendu

47

2025

import { AppBar, Toolbar, Typography } from '@material-ui/core';

ReactDOM.render(

<React.StrictMode>

<AppBar position="static">

<Toolbar>

<Typography variant="h6"> Appli démo UBO </Typography>

</Toolbar>

</AppBar>

<Compteur />

</React.StrictMode>,

document.getElementById('root')

);

48 of 191

Les dépendances

Et on obtient une app avec un barre de navigation material design sans faire de css

48

2025

49 of 191

Les dépendances

Si plusieurs dépendances sont dans le même package, il est possible d’utiliser des accolades pour toutes les importer d’un coup.

49

2025

import {Button, Card, CardActions, CardContent} from "@material-ui/core";

50 of 191

Les dépendances

Pour arriver au même résultat avec des composants qu’on a défini soit même, il faut ajouter dans le dossier un fichier index.js regroupant les exports de composants.

Par défaut, si le nom du fichier n’est pas précisé, React prend toujours le fichier index.js

50

2025

import LeagueDetail from "./LeagueDetail";

import Leagues from "./Leagues";

import LeagueSummary from "./LeagueSummary";

export {Leagues, LeagueSummary, LeagueDetail}

import {Leagues, LeagueDetail} from "../leagues";

51 of 191

Les dépendances

Penser à mettre à jour régulièrement les dépendances avec npm-check-updates pour profiter des dernières fonctionnalités, des correctifs de bugs et surtout pour limiter le nombre de vulnérabilités.

51

2025

52 of 191

Créer un composant

2025

53 of 191

JSX

Le JSX est une extension syntaxique de JavaScript permettant de définir une variable JavaScript à partir d’une balise HTML

53

2025

const element = (

<h1 className="greeting">

Bonjour, monde !

</h1>

);

const element = React.createElement(

'h1',

{className: 'greeting'},

'Bonjour, monde !'

);

54 of 191

JSX

54

2025

55 of 191

3 façons d’instancier un composant

  1. Render : Permet d’injecter un composant dans un élément du DOM. C’est ce qu’on retrouve dans index.js

A n’utiliser que pour le composant racine.

55

2025

import ReactDOM from 'react-dom';

ReactDOM.render(

<div>Mon composant</div>,

document.getElementById('root')

);

56 of 191

3 façons d’instancier un composant

2) Composant fonctionnel

56

2025

export function App() {

return (

<div>Mon composant</div>

);

}

57 of 191

3 façons d’instancier un composant

3) React.Component

La variable state est un objet qui définit l’état du composant

La fonction render() est chargée du rendu du composant

Les { } permettent d’injecter des variables

57

2025

class Compteur extends React.Component {

state = {

compteur: 0

}

render() {

return (

<span>{this.state.compteur}</span>

);

}

}

58 of 191

3 façons d’instancier un composant

3) React.Component

Une variable injectée peut elle même être du JSX

58

2025

const stateDisplay = <h1>{this.state.compteur}</h1>;

return (

<span>{stateDisplay}</span>

);

59 of 191

3 façons d’instancier un composant

⚠️ Chacune des méthodes précédentes ne prend en paramètre qu’un seul élément JSX.

Si vous avez plusieures balises pour la vue de votre composant, elles doivent être encapsulées dans un élément parent tel qu’une <div> ou un <Fragment>

59

2025

60 of 191

3 façons d’instancier un composant

⚠️ Chacune des méthodes précédentes ne prend en paramètre qu’un seul élément JSX.

60

2025

return (

<h1>title</h1>

<span>content</span>

);

return (

<div>

<h1>title</h1>

<span>content</span>

</div>

);

61 of 191

3 façons d’instancier un composant

La balise <Fragment> disparaît lors du rendu.

Elle permet de définir un composant ou une variable JSX contenant plusieurs éléments sans ajouter de couche supplémentaire dans le DOM.

Elle peut être abrégée

en balise vide.

61

2025

<>

<h1>title</h1>

<span>content</span>

</>

62 of 191

Les fonctions

Fonction de base :

incrémentation d’un compteur

62

2025

const [compteur, setCompteur] = useState(0);

const increment = () => {

setCompteur(compteur+1);

}

return (<>

<Button variant="contained" color="primary" onClick={increment}>Clic</Button> :

{ compteur }

</>);

63 of 191

Les fonctions

⚠️ Attention à la syntaxe :

  • onClick avec un “C” majuscule
  • des { } et pas de “ ”
  • pas de () après le nom de la fonction (sinon appel à chaque affichage).

63

2025

onClick={increment}

64 of 191

Les fonctions : bases

Si je modifie ma fonction de la sorte, je devrais avoir une popup qui m’affiche la valeur de mon compteur : 0

64

2025

increment() {

alert(compteur);

}

65 of 191

Les fonctions : bases

Perdu !

Définie comme telle, la fonction n’a pas accès au state (et donc à la valeur de mon compteur).

65

2025

Uncaught TypeError: Cannot read property 'state' of undefined

66 of 191

Les fonctions

Pour que la fonction soit exécutée dans le contexte du composant et ait accès à l’instance et donc au state, il y a 2 solutions :

66

2025

handleClick() {

alert(compteur);

}

<button

onClick={() => handleClick()}>

Push Me</button>

handleClick = () => {

alert(compteur);

}

<button onClick={handleClick}>

Push Me</button>

👍

👎

67 of 191

Les fonctions

⚠️ Il est possible d’utiliser une fonction fléchée (() =>) dans la méthode render() et ça peut être pratique pour passer des arguments en paramètre de l’appel ; mais ça créera une nouvelle instance de la fonction à chaque fois que la méthode render() est appelée, ce qui peut impacter négativement les performances.

67

2025

onClick={() => handleClick()}

68 of 191

Les fonctions -> le state

On met à jour notre fonction pour incrémenter le compteur

68

2025

handleClick = () => { // composant Fonctionnel

setCompteur(compteur+1);

}

handleClick = () => { // composant Class

this.setState({compteur: this.state.compteur + 1});

}

69 of 191

Le state

🚨 En React, le state est immutable

69

2025

70 of 191

Le state est immutable

🚨 En React, le state est immutable

On ne peut pas juste

incrémenter directement

le state.

React ne saurait pas que le state a changé et que la vue doit être rafraîchie

70

2025

handleClick = () => {

compteur++;

}

71 of 191

Le state est immutable

=> Il faut utiliser la fonction setter retournée par useState() pour indiquer à React de modifier le state.

71

2025

72 of 191

Les fonctions

Victoire

72

2025

73 of 191

Les hooks

2025

74 of 191

Les hooks

Depuis React 16.8, grâce aux “hooks”, les composants fonctionnels peuvent avoir un state et faire pratiquement tout ce que permettent les composant définis comme classe héritant de React.Component

74

2025

75 of 191

Les hooks

Les 2 principaux hooks permettant de gérer le state et l’état du composant.

75

2025

import {useState, useEffect} from 'react';

const [page, setPage] = useState(1);

useEffect(() => {

console.log("component update");

}, [page]);

76 of 191

Les hooks

La fonction useState() permet de définir un state.

Elle peut être appelée plusieurs fois pour définir plusieurs “morceaux” de state.

Elle prend en paramètre l’état initial du state et fournit un couple d'éléments : le 1er contient la valeur du state et le 2ème contient une référence vers la fonction permettant de mettre à jour ce state.

76

2025

77 of 191

Les hooks

La fonction useEffect() est appelée à chaque mise à jour du composant.

Elle permet à la fois d’initialiser le composant et de réagir à certaines actions de l’utilisateur.

Pour éviter les traitements inutiles, elle peut avoir un 2ème paramètre optionnel contenant une liste de variables telles que la fonction useEffect() ne soit appelée que si l’une de ces variables est modifiée.

Dans l’exemple précédent, on ne log que si l’utilisateur a changé de page.

77

2025

78 of 191

Les hooks

useReducer() fournit une alternative à useState() pour la gestion d’état plus complexes. Il prend en paramètre un reducer (fonction du type (state, action) => newState).

useMemo() permet d’optimiser les perfs lors des rendus en gardant en cache la valeur de certaines données lorsque les paramètres nécessaires à leurs calculs sont identiques.

NB : sera obsolète dans la prochaine version (v19) car géré nativement par le nouveau compilateur : https://react.dev/learn/react-compiler

78

2025

79 of 191

Les hooks

Certaines librairies, notamment react-router définissent également leurs propres hooks qu’il est possible d’utiliser.

🚨 Il n’est pas possible d’utiliser les hooks dans des composants “classiques” définis comme classes héritant de React.Component.

79

2025

80 of 191

Rendu du composant

2025

81 of 191

Rendu du composant

Composant simple avec affichage d’une variable

81

2025

return (

<div>

<button onClick={handleClick}>Push Me</button> : {compteur}

</div>

);

82 of 191

Rendu du composant

Possibilité d’initialiser des variables avant la vue

Les variables peuvent être des éléments JSX

82

2025

const quote = this.state.quote;

return (

<div className="App">{quote.saying}

...

83 of 191

Rendu du composant

Appel de fonction pour construire des morceaux de vue

83

2025

favoriteBuilder(favorite) {

return favorite?<FavoriteIcon/>:<FavoriteBorderIcon/>;

}

return (

<div className="App">

{this.favoriteBuilder(quote.favorite)}

...

84 of 191

Rendu du composant

Affichage d’une liste avec la fonction Array.map()

84

2025

return (

<div className="App">

{this.state.quotes.map(quote =>

<Card className="card" key={quote.id}><CardContent>

{quote.saying}

</CardContent></Card>

)}

</div>

);

85 of 191

Rendu du composant

Noter l’utilisation de key={quote.id}

Cet attribut permet à React d’identifier les différents éléments de la liste et d’optimiser la mise à jour de leur rendu

La clé doit être unique et invariante dans la liste

Ex : utiliser un id et pas un index si la liste risque d’être triée

Il n’est pas obligatoire, mais React affichera un avertissement s’il n’est pas présent

85

2025

86 of 191

Les props

2025

87 of 191

Les props

Dès que le composant devient compliqué, il convient de créer des sous-composants.

Pour passer des paramètres à ces sous composants, on utilise les props.

87

2025

88 of 191

Les props

Les props sont passées en paramètre comme des attributs XML

Elle peuvent être des variables primitives (int, float, string, ...), des objets ou des fonctions (callback pour rappeler le parent)

Elles peuvent être du JSX : pratique pour afficher du contenu dans un composant de mise en forme, type popup.

88

2025

<Quote saying={quote.saying} author={quote.author}/>

89 of 191

Les props

Si le composant appelé est un composant fonctionnel, on récupère les props en paramètre de la fonction :

89

2025

export default function MonComposant({ saying, children, handleFavorite }) {

return (

<>...</>

)

}

90 of 191

Les props - old

Dans le composant appelé de type class, on récupère les props via this.props

S’il y a plusieurs props, on peut toutes les affecter d’un coup avec l’initialisation { }

90

2025

const saying = this.props.saying;

OU

const {saying, author} = this.props;

91 of 191

Les props

Quand les props sont de type JSX (pour la délégation de contenu), les fonction du package React.Children permettent de faciliter leur manipulation : map, forEach, count, …

91

2025

92 of 191

Les props

🚨 comme le state, les props sont en lecture seule

92

2025

93 of 191

Les props

🚨 comme le state, les props sont en lecture seule

=> Pour mettre à jour une prop, il faut donc passer en prop une fonction, définie dans le composant parent, qui va mettre à jour la variable injectée en prop

93

2025

94 of 191

Les props et le state

Le state est mis à jour de façon asynchrone et mutualisé

Dans un composant Class, si besoin de mettre à jour le state en fonction des props, utiliser la fonction suivante :

94

2025

this.setState((state, props) => ({

counter: state.counter + props.increment

}));

95 of 191

Les formulaires

2025

96 of 191

Les formulaires

En React, on cherche à faire des Single Page App.

Le composant gère les données et l’envoi du formulaire sans changer de page.

Il existe 4 façons de gérer les champs de formulaire :

  1. En liant le champ au state du composant
  2. En créant des références
  3. En utilisant l’API FormData

4) <form> : https://react.dev/reference/react-dom/components/form

96

2025

97 of 191

Les formulaires - gestion via le state

On lie le champ à une propriété du state (ici value)

On récupère la nouvelle valeur via l’événement de modification et on met à jour le state

97

2025

<input type="text" value={value} onChange={handleChange}/>

handleChange = (event) => {

setValue(target.value);

}

98 of 191

Les formulaires - gestion via le state

La mise en place d’une fonction onChange est indispensable, sinon le state ne sera pas mis à jour et l’affichage non plus.

* Relativement lourd dans les formulaires contenant beaucoup de champ, mais pratique pour les contrôles de surface et la gestion des erreurs.

98

2025

<input type="text" value={value} onChange={handleChange}/>

handleChange = (event) => {

setValue(target.value);

}

99 of 191

Les formulaires - références

On créé une ref : inputRef = useRef(null);

On l’associe au champ : ref={inputRef}

On récupère sa valeur : inputRef.current.value

99

2025

inputRef = useRef(null);

<input type="text" name="inputRef" defaultValue="test" ref={inputRef} />

alert('Ref input : ' + inputRef.current.value);

100 of 191

Les formulaires - références

On créé une ref : inputRef = React.createRef();

On l’associe au champ : ref={this.inputRef}

On récupère sa valeur : this.inputRef.current.value

100

2025

inputRef = React.createRef();

<input type="text" name="inputRef" defaultValue="test" ref={this.inputRef} />

alert('Ref input : ' + this.inputRef.current.value);

101 of 191

Les formulaires - références

🚨 Certains composants comme material-ui ne supportent pas les refs ou les intègrent via une autre propriété (ici inputRef)

De préférence, utiliser la gestion via le state

101

2025

<TextField name="vainputReflue" label="inputRef" defaultValue="test" inputRef={inputRef} variant="outlined" className="form-element" />

102 of 191

Les formulaires - références

Les refs peuvent également servir à référencer des variables lambda, propres au composant, qui ne sont pas réinitialisées à chaque rendu.

Il s’agit d’un des rare élément mutable de React (i.e. qui peut être modifié directement).

La modification d’une ref ne déclenche pas une mise à jour du rendu (la valeur d’une ref affichée ne sera pas modifié)

102

2025

103 of 191

Les formulaires - FormData

Interface permettant de récupérer tous les champs d’un formulaire sous forme de Map.

103

2025

const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {

event.preventDefault();

const form = event.currentTarget;

const data = new FormData(form);

loginUser({username: data.get('login') as string, password: data.get('password') as string}

}

104 of 191

Les formulaires - submit

On défini la fonction d’envoi du formulaire

🚨 Ne pas oublier d’appeler la fonction preventDefault() pour bloquer le rechargement de la page

104

2025

handleSubmit = (event) => {

event.preventDefault();

/* j’enregistre mes données de formulaire */

}

...

<form onSubmit={handleSubmit}>

105 of 191

Les formulaires - <form>

Depuis la version 19, react a introduit l’attribut action permettant de passer une fonction à la validation du formulaire (à la place du onSubmit)

105

2025

export default function Search() {

function search(formData) {

const query = formData.get("query");

alert(`You searched for '${query}'`);

}

return (

<form action={search}>

<input name="query" />

<button type="submit">Search</button>

</form>

);

}

106 of 191

Appels API

2025

107 of 191

Appels API

On utilise la fonction fetch

On récupère le résultat en tant que JSON

On met à jour le state avec le résultat

On tient compte des erreurs éventuelles

107

2025

fetch("http://api.fr")

.then(res => res.json())

.then(

(result) => {

this.setState({

quote: result

});

},

(error) => {

this.setState({error});

}

)

108 of 191

Appels API

La fonction fetch peut également prendre un objet en paramètre pour définir le type de méthode HTTP, les données et les headers envoyés.

108

2025

fetch("/login", {

method: "POST",

body: datas,

headers: { "Content-Type" : "application/json" }

})

109 of 191

Appels API

Le hook useEffect() qui permet d’exécuter du code au chargement du composant ou lors de la modification de certaines données est l’endroit idéal pour déclencher des appels API.

Il permet d’initialiser les données du composant à sa création et de les rafraîchir quand souhaité.

109

2025

110 of 191

Appels API

Les applications React sont statiques. Elles n’ont pas besoin d’un serveur d’application comme Tomcat ou d’un runtime NodeJs, Java, Python, ou autre.

C’est un énorme avantage en terme d’hébergement car il suffit que les éléments du site soient accessible en ligne, ce qui autorise une multitude de solutions bon marché : serveur Apache ou NGinx, CDN, Bucket S3 / Cloud Storage, espace Github Pages, ...

Il reste tout de même la partie Back / API à héberger par ailleurs, mais dans ce contexte, les solutions serverless prennent tout leur sens.

110

2025

111 of 191

Appels API

La partie API est généralement constituée :

  • D’un serveur Node.js embarqué avec l’application.

Les frameworks les plus courants sont NestJS et Express.

  • Ou de fonctions serverless comme : AWS Lambda / Google Cloud Functions

Plutôt que de mettre les url d’API (et ses éventuels secrets) directement dans le composant, il est d’usage soit de les externaliser dans un fichier de conf, soit de les mettre en variable d’environnement.

111

2025

112 of 191

Appels API

Pour utiliser les variables d’environnement :

  • Créer un fichier .env à la racine du projet
  • Définir sa variable.

Ex : REACT_APP_QUOTES_API_URL=http://api.quotable.io/random

  • La variable est alors accessible dans le composant via la notation process.env.REACT_APP_QUOTES_API_URL

🚨 Toutes les variables d’environnement accessibles dans l’app doivent commencer par “REACT_APP_”, afin d’éviter l’exposition accidentelle de variables d’environnement sensibles.

112

2025

113 of 191

Gestion des données

2025

114 of 191

Gestion des données

Dans un monde idéal, chaque composant est responsable des ses données et le système de props suffit à faire interagir les différents composants.

Mais sur des applications plus complexes, plusieurs composants peuvent avoir besoin de partager les mêmes données.

114

2025

115 of 191

Gestion des données

Solution n°1 : faire remonter l’état

Si 2 composants ont besoin d’une même donnée, il suffit de la stocker dans le parent le plus proche et de la faire redescendre via les props des composants fils.

Mais quand l’application devient plus complexe, ça peut générer beaucoup de props qu’il faut transmettre par des composants intermédiaires qui n’en ont pas l'utilité.

115

2025

116 of 191

Gestion des données

Solution n°2 : composition ou délégation de contenu

Plutôt que de passer en props l’ensemble des éléments nécessaires pour construire l’un des composant fils, on défini un composant fonctionnel qu’on passe en paramètre.

Très utile pour les composants génériques type dialog.

116

2025

117 of 191

Gestion des données

Solution n°2 : délégation de contenu

117

2025

<Route path="/favorite" component={Favorite} />

function Favorite() {

return (

<div className="App">

<Quote saying="Ma citation préférée" author="Moi" />

</div>

);

}

118 of 191

Gestion des données

Solution n°3 : le contexte

On définit un objet de contexte au niveau du composant parent, lié au state de ce composant.

Tous les composants enfant peuvent s’abonner aux mises à jour de ce contexte.

Le contexte peut contenir des références à des fonctions permettant de modifier le contexte au niveau du composant parent.

Le composant parent reste responsable des données, mais le contexte permet de limiter l’utilisation des props.

118

2025

119 of 191

Gestion des données

Solution n°3 : le contexte

On crée une référence de Context dans un fichier dédié

On englobe des composant fils grâce à la balise .Provider et on lie au state

119

2025

export const MyContext = createContext();

<MyContext.Provider value={value}>

const value = useContext(MyContext);

On associe la référence au context du composant fils avec .contextType et on peut utiliser le contexte via la fonction useContext()

120 of 191

Gestion des données

Il est possible d’utiliser le contexte pour créer un “store” contenant tous les objets de l’application et toutes les fonctions permettant d’en modifier l’état.

Pour les petits projets, c’est une méthode intéressante permettant de s’affranchir de librairies supplémentaires.

🚨Le context peut vite devenir fourre-tout ; et lorsque qu’il est modifié, tous les composants qui en dépendent sont re-rendus. Même si React est prévu pour ça, sur de gros projets, les performances peuvent s’en trouver dégradées.

120

2025

121 of 191

Gestion des données

Solution n°4 : externaliser la gestion des données

Plutôt que de centraliser les données au niveau des composants parents, on créer un store dédié à la gestion des données et indépendant des composants.

Pour ce faire, la librairie la plus

populaire est Redux

121

2025

"dependencies": {

"@reduxjs/toolkit": "^1.4.0",

"react-redux": "^7.1.3"

}

122 of 191

Gestion des données - Redux

122

2025

123 of 191

Gestion des données - Redux

Redux se base sur l’architecture “Flux” mise au point par Facebook

123

2025

124 of 191

Gestion des données - Redux

Sur une architecture Model - View, les vues utilisent parfois plusieurs modèles qui sont eux-même utilisés par plusieurs vues. On peut se retrouver avec des événements qui bouclent et des états inconsistants et compliqués à débugger.

L’architecture Flux est linéaire, il y a un seul flux de données.

Toutes les données sont dans le store. Les vues envoient des actions pour modifier l’état du store. Le dispatcher centralise les actions (fonctionnelles) et les traduit en mises à jour du store. Les vues s’abonnent aux modifications des données du store pour rester à jour.

124

2025

125 of 191

Gestion des données - Redux

🚨 Pour éviter les incohérences d’état toujours privilégier le stockage de données brutes plutôt que de données déduites / calculées.

Définir ensuite des selector pour extraire du store les données utiles aux vues.

Ex : pour afficher un nombre de messages non lu, il vaut mieux stocker la liste des messages non lus, plutôt qu’un compteur qui risque de se retrouver déphasé avec la réalité.

125

2025

126 of 191

Gestion des données - Redux

On ajoute à notre projet la dépendance react-redux.

La dépendance @types permet l’utilisation en typescript

On n’hésite surtout pas à ajouter également @reduxjs/toolkit qui offre du sucre syntaxique pour faciliter l’écriture des reducers et gérer les différents états du store.

La suite du cours se base sur

l’utilisation de redux avec le

toolkit.

126

2025

"dependencies": {

"@reduxjs/toolkit": "^1.8.6",

"@types/react-redux": "^7.1.24",

"react-redux": "^8.0.4",

}

127 of 191

Gestion des données - Redux

Il est possible de créer un nouveau projet avec redux déjà intégré et pré-configuré :

NB : reduxjs/toolkit est une librairie JS utilisable indépendamment de React.

127

2025

npx degit reduxjs/redux-templates/packages/vite-template-redux my-app

128 of 191

Gestion des données - Redux

On défini un morceau de store (slice) contenant une variable

counter

On définit un reducer (dispatcher) contenant une fonction increment permettant de modifier la donnée dans le store

On exporte le tout

128

2025

export const counterSlice = createSlice({

name: 'counter',

initialState: { value: 0 },

reducers: {

increment: state => {

state.value += 1;

},

},

});

export const {increment} = counterSlice.actions;

export default counterSlice.reducer;

129 of 191

Gestion des données - Redux

La fonction createAsyncThunk permet de définir des actions asynchrones.

Très utile pour les appels API.

On peut définir plusieurs extraReducers (pending, fulfilled, rejected) pour mettre à jour le store (et donc la vue) en fonction du statut de la requête.

129

2025

const fetchUserById = createAsyncThunk(

'users/fetchByIdStatus',

async (userId, thunkAPI) => {

const response = await userAPI.fetchById(userId)

return response.data

}

)

[...]

extraReducers: (builder) => { builder.addCase(fetchUserById.fulfilled, (state, action) => {

state.entities.push(action.payload)

})

},

130 of 191

Gestion des données - Redux

On configure un store avec le reducer précédemment défini dans le fichier store.js

Ce store référencera tous les reducer des différents Slices de l’application.

130

2025

import { configureStore } from '@reduxjs/toolkit';

import counterReducer from './counterSlice';

export default configureStore({

reducer: {

counter: counterReducer,

},

});

131 of 191

Gestion des données - Redux

On englobe le ou les composants qui vont utiliser ces données dans un Provider utilisant le store qu’on a défini.

131

2025

import store from './store';

import { Provider } from 'react-redux';

render() {

return (

<Provider store={store}>

<Router/>

</Provider>

);

}

132 of 191

Gestion des données - Redux

La fonction useSelector permet de récupérer les infos dans le store.

La fonction useDispatch permet d’appeler un reducer pour mettre à jour les données du store.

132

2025

export function ReduxCount() {

const count = useSelector(state => state.counter.value);

const dispatch = useDispatch();

return (

<span>

<Button onClick={() => dispatch(increment())}> Push Me</Button> : {count}

</span>

);

}

133 of 191

Gestion des données - Redux

Tips : La fonction useEffect est votre meilleur allié pour utiliser le useDispatch afin d’initialiser les données du composant ou de les mettre à jour à chaque fois qu’un élément du store récupéré via useSelector est modifié.

133

2025

134 of 191

Gestion des données - Redux

Tips : sous Chrome, utiliser l’extension Redux DevTools pour tracer les mises à jour du store.

134

2025

135 of 191

Gestion des données - TD

TD : PokeAPI

Créer 3 composants : générations, jeux et pokemons communiquant par l’intermédiaire d’un store constitué de 2 slices : un pour les générations (endpoint /generation) et l’autre pour le détail de la génération sélectionné (endpoint /generation/x)

Pour les plus rapides, ajouter un champ de recherche pour filtrer les pokémons par nom.�

135

2025

136 of 191

Gestion des données

136

2025

137 of 191

Gestion des données

Projet de Facebook, se voulant être

une alternative simple et efficace à Redux.

Les données du store sont définies par des Atomes.

Des sélecteurs permettent d’exposer aux vues des données dérivées d’atomes ou d’autres sélecteurs.

Ceux-ci sont nativement compatibles avec les requêtes API asynchrones et gèrent la mise en cache des données.

Projet malheureusement abandonné et incompatible avec React v19.

137

2025

138 of 191

Gestion des données

Approche bien plus simple :

On défini des variables qui ne seront accessible qu’en lecture seule depuis les composant et des fonctions permettant de manipuler le store.

138

2025

import { create } from 'zustand'

const useBear = create((set) => ({

bears: 0,

increasePopulation: () => set((state) => ({ bears:

state.bears + 1 })),

removeAllBears: () => set({ bears: 0 }),

updateBears: (newBears) => set({ bears: newBears }),

}))

139 of 191

Gestion des données

139

2025

export const counter = atom<number>({

key: 'counter',

default: 1,

});

export const asyncDataState = selector({

key: 'asyncDataState',

get: async () => {

const response = await fetch(apiUrl, {});

return await response.json() as MyDataResponse;

}

});

export const subDataState = selector({

key: 'subData',

get: async ({get}) => {

return get(asyncDataState).sub_object

}

});

140 of 191

Gestion des données

140

2025

const myData = useRecoilValue(asyncDataState);

const [counter, setCounter] = useRecoilState('counter');

141 of 191

Gestion des données - sauvegarde

Le state, le context ainsi que Redux sont effacés à chaque fois que la page est rafraichie.

Pour sauvegarder des données, pensez à utiliser les cookies, le sessionStorage et le localStorage.

  • le sessionStorage est effacé lorsque l’onglet est fermé
  • le localStorage n’a pas de limite de conservation et est lié au domaine

🚨 Attention au stockage d’informations sensibles (jwt, token) car elles seraient accessibles par tous les scripts Js de la page.

141

2025

142 of 191

Le routage

2025

143 of 191

Le routage

Même dans le cas d’une Single Page App, on veut parfois définir plusieurs pages afin de faciliter la navigation et l’ajout aux favoris.

C’est facile grâce à react-router-dom

/!\ Attention la version 6 n’est pas rétro-compatible avec la version 5 et de nombreux tutoriels et forums sont basés sur l’ancienne version.

En cas de doute, se référer à la documentation de migration

143

2025

144 of 191

Le routage

On définit les menus de notre site web et les pages associées.

144

2025

<Router>

<div>

<nav>

<ul>

<li><Link to="/">Home</Link></li>

<li><Link to="/about">About</Link></li>

</ul>

</nav>

...

</div>

</Router>

145 of 191

Le routage

Puis on défini les composants associés à chaque page

145

2025

<Router>

<div>

...

<Routes>

<Route path="/about">

<About />

</Route>

<Route path="/">

<Home />

</Route>

</Routes>

</div>

</Router>

146 of 191

Le routage

Par défaut, si on définit la route “/” en dernier, elle fait office de page par défaut pour toutes les URLs restantes.

Si on veut définir une page “not found” différente de la page d'accueil, il faut spécifier la route “/” comme exact et ajouter une route “*”

146

2025

<Router>

<div>

...

<Routes>

<Route exact path="/">

<Home />

</Route>

<Route path="*">

<NoMatch />

</Route>

</Routes>

</div>

</Router>

147 of 191

Le routage

On peut définir des routes avec paramètres.

Dans ce cas, il est préférable de passer le composant cible via l’attribut component plutôt que de le déclarer comme enfant de l’élément Route.

Ainsi, les paramètres sont automatiquement passés au composant via les props.

147

2025

<Router>

<div>

...

<Routes>

<Route path="/number/:myNumber" component={RouterTest} />

</Routes>

</div>

</Router>

148 of 191

Le routage

Si on a passé le composant cible via l’attribut component on peut utiliser les props pour récupérer les paramètres d’url et le path complet.

Dans tous les cas, on peut aussi les récupérer via les fonctions useParams() et useLocation()

148

2025

import {useLocation, useParams} from "react-router-dom";

render() {

return (

{props.match.params.myNumber} - {useParams().myNumber}

{props.location.pathname} - {useLocation().pathname}

);

}

149 of 191

Le routage

On peut définir des redirections entre les routes.

Pratique pour associer plusieurs paths à la même route ou pour définir des routes par défaut.

149

2025

<Route path="/number/:myNumber" component={RouterTest} />

<Route path="/number">

<Navigate to="/number/42" />

</Route>

<Route path="/nombre">

<Navigate to="/number" />

</Route>

150 of 191

Le routage

On a également accès à l’historique pour revenir sur la page précédente.

D’autres fonctions permettent de revenir en arrière de plusieurs pages d’un coup ou de retourner vers le futur.

150

2025

import {useHistory} from "react-router-dom";

let history = useHistory();

function goBack() {

history.goBack();

}

Jusqu’à React Router v5

151 of 191

Le routage

On a également accès à l’historique pour revenir sur la page précédente.

D’autres fonctions permettent de revenir en arrière de plusieurs pages d’un coup ou de retourner vers le futur.

151

2025

import {useNavigate} from "react-router-dom";

let navigate = useNavigate();

function goBack() {

navigate(-1);

}

Depuis React Router v6

152 of 191

Chargement dynamique

Par défaut, React package tous les composants dans un seul fichier JS qui est chargé lors du premier affichage du site.

Plus l’app grossit, plus ce fichier peut être volumineux et long à charger.

Pour pallier ça il est possible de découper l’app en plusieurs fichiers JS qui seront chargés au fur et à mesure de l’utilisation des composants.

Le découpage se fait automatiquement lors du build de l’application en fonction des imports.

152

2025

153 of 191

Chargement dynamique

Import dynamique d’un composant

Utilisation de la balise Suspense pour

afficher le composant Loading

pendant le chargement d’un composant

dynamique.

153

2025

import lazy from 'react';

const FormDemo = lazy(() => import('./FormDemo'));

import Suspense from 'react';

<Suspense fallback={Loading}>

....

</Suspense>

154 of 191

Le rendering

2025

155 of 191

Le rendering - Core Web Vitals

Les performances des sites web sont évaluées en fonction du First Contentful Pain (FCP), du Largest Contentful Pain (LCP) et du Time To Interactive (TTI).

- FCP : début de l’affichage de la page (éventuellement une page blanche)

- TTI : durée avant que le client puisse interagir avec la page

- LCP : affichage final de la page, avec son contenu

155

2025

156 of 191

Le rendering - Core Web Vitals

Exemple de rapport Lighthouse

sur la page d’accueil du site de

l’UBO

(disponible depuis les outils de

développement Chrome)

156

2025

157 of 191

Le rendering - Core Web Vitals

Le template d’application React par défaut contient normalement une fonction reportWebVitals() dans le fichier index.js

En ajoutant console.log en paramètre, le navigateur va venir logger automatiquement tous ces paramètres.

157

2025

158 of 191

Le rendering - Search Engine Optimisation

Le SEO regroupe l’ensemble des techniques visant à améliorer le référencement de son site web, afin d’arriver en tête des résultats des moteurs de recherche :

  • Nombre de liens entrants, sortants et inter-pages.
  • Métadonnées du site (titre et autres balises en <head>)
  • Contenu du site (mots clé)
  • Ergonomie du site (adapté au mobile et aux non voyants)
  • Poids et vitesse de chargement du site

158

2025

159 of 191

SEO avec React Helmet

React Helmet permet de définir les attributs de l’entête de la page HTML (balise <head>), afin d’améliorer l’indexation.

Il est possible d’utiliser la balise

<Helmet> dans différents

composants. Suivant le type

d’attribut, soit ils s’additionnent,

soit la valeur de l’attribut du

composant le plus imbriqué écrase

celle du composant parent.

159

2025

<Helmet>

<title>Page {myNumber}</title>

<meta name="description" content="Number page"/>

</Helmet>

160 of 191

SEO

Depuis la version 19, React supporte nativement les balises <title>, <link> et <meta> dans les composants.

160

2025

161 of 191

Le rendering

2 approches s’opposent pour générer le rendu des pages web :

  • SSR : Server-Side Rendering

  • CSR : Client-Side Rendering

161

2025

162 of 191

Le rendering : Server-Side Rendering (SSR)

Le serveur web génère et envoie au client une page HTML complète contenant déjà toutes les données de l’application et du client.

Le javascript n’est utilisé que pour les interactions utilisateur basiques.

C’est l’approche “à l’ancienne” utilisée par PHP, JSP et ASP .NET.

Inconvénients : peu adapté aux SPA et nécessite un webserver performant.

Avantages : affichage quasi-immédiat de la page une fois reçue par le client et plus performant en terme de SEO (Search Engine Optimisation)

162

2025

163 of 191

Le rendering : Client-Side Rendering (CSR)

Le serveur web envoie un squelette vide et toute la page est générée par le navigateur client.

Il faut généralement plusieurs appels API pour récupérer toutes les données nécessaires, puis la construction de la page en javascript peut être longue.

C’est l’approche des SPA et des frameworks comme React.

Inconvénients : 1er chargement long et pas optimisé pour la SEO.

Avantages : bonne interactivité une fois l’application chargée

163

2025

164 of 191

Le rendering : Static Rendering

Il est heureusement possible de mélanger les 2 afin de profiter de tous les avantages :

=> les principales pages peuvent être pré-rendues au build (ou à la demande).

Le client reçoit alors une page déjà construite et qu’il ne reste qu’à hydrater (attacher les actions javascript aux différents éléments de la page).

L’affichage initial est plus rapide et les pages statiques ont du contenu leur permettant d’être mieux indexées par les moteurs de recherche.

164

2025

165 of 191

Optimisations - Static Rendering

react-snap

165

2025

"scripts": {

"postbuild": "react-snap",

},

"reactSnap": {

"puppeteerArgs": ["--no-sandbox"]

}

const rootElement = document.getElementById("root");

if (rootElement.hasChildNodes()) {

hydrateRoot(rootElement).render(<App/>);

} else {

createRoot(rootElement).render(<App/>);

}

166 of 191

Microfrontend

2025

167 of 191

Microfrontend

Lorsqu’une application Web devient trop volumineuse, la gestion peut vite devenir laborieuse :

  • Conflits lorsque plusieurs équipes travaillent en parallèle
  • Planification des livraisons (quelles évolutions à quelle date ?)
  • Difficulté à tester tout le périmètre

=> découper le site web en plusieurs morceaux

167

2025

168 of 191

Microfrontend - iframe

L’approche la plus ancienne et basique : utiliser la balise <iframe>

Celle-ci permet d’intégrer un site web dans un autre site web.

Avantages :

  • pratique pour intégrer des widgets autonomes (ex : réseaux sociaux)

Inconvénients :

  • extrêmement lourd car le navigateur doit charger plusieurs sites web pour une même page
  • la communication entre la page et l’iframe ; et surtout le redimensionnement de l’iframe est compliqué

168

2025

169 of 191

Microfrontend - reverse proxy

Utiliser un reverse proxy type NGINX pour rediriger les paths vers différentes applications

Avantages :

  • permet de jongler facilement avec des framework différents
  • chaque équipe est autonome sur son application

Inconvénients :

  • les transitions entre les applications sont moins fluide
  • il faut assurer une cohérence graphique et technique (session)
  • certains éléments (header, menu) doivent être dupliqués dans chaque app

169

2025

170 of 191

Microfrontend - librairies

Avoir une application ”socle”, qui importe des vues définies dans plusieurs libs

Avantages :

  • une seule application, mais plusieures bases de code
  • chaque équipe est autonome sur les développements de sa lib

Inconvénients :

  • comme l’intégration des différentes libs se fait lors du build, il faut re-livrer le socle à chaque fois qu’un module doit être mis à jour

170

2025

171 of 191

Microfrontend - Module Federation

Utilisation de Module Federation

Permet de découper un site web en une application Host qui sert de socle et en plusieurs applications Remote qui exposent leur composants sous forme de fichiers JS compilés.

Le découpage est le même qu’avec des librairies, mais avec un chargement dynamique de chaque version

=> les équipes peuvent livrer leur Remote en toute autonomie, sans avoir besoin de re-livrer le Host à chaque fois.

171

2025

172 of 191

Les styles

2025

173 of 191

Les styles

3 façons de définir les styles :

  • En inline, mais vous vous ferez insulter par le compilateur car ce n’est pas une bonne pratique.

  • Via des librairies permettant de définir les styles en JavaScript directement dans les fichiers JSX.

173

2025

174 of 191

Les styles

3 façons de définir les styles :

  • Via des fichiers css importés par les composants. Ça permet de scoper les styles par composant ou par famille de composants.

Il est également possible d’utiliser des pre-processeur CSS comme SASS ou des framework CSS tels que tailwindcss.

174

2025

175 of 191

Les styles - utilisation classique

On définit le style des différents éléments du composant dans un fichier css dédié au composant.

On importe le fichier css dans le composant et on utilise l’attribut className pour référencer les classes définies dans le fichier CSS.

175

2025

Dans le fichier moncomposant.module.css :

.select {

width: 200px;

display: inline-block;

margin-top: 100px;

}

Dans le composant :

import styles from "./moncomposant.module.css";

<div className={styles.select}>

176 of 191

Le linter

2025

177 of 191

ESLint

React intègre ESLint par défaut pour détecter les erreurs ou les mauvaises pratiques de code.

Il est configuré dans le fichier package.json :

177

2025

"eslintConfig": {

"extends": [

"react-app",

"react-app/jest"

]

}

🚨 Certaines erreurs du linter ne sont pas bloquantes en mode développement, mais elles le sont lors d’un build, afin d’éviter les comportements imprévus à l’usage.

=> Pensez à vérifier les erreurs (et les warning) avant de publier votre application !

178 of 191

ESLint

Il est possible de configurer le linter via un fichier .eslintrc, afin : d’ajouter des plugins (effectuant des contrôles supplémentaires), de forcer certaines règles facultatives ou d’en désactiver certaines.

Ex : accessibilité ou formateur de code (Prettier)

178

2025

{

"extends": ["react-app", "plugin:jsx-a11y/recommended", "prettier"],

"plugins": ["jsx-a11y", "prettier"]

}

179 of 191

ESLint

Un utilitaire est disponible pour générer un fichier .eslintrc par défaut en fonction des caractéristiques du projet : eslint

179

2025

npm install eslint --save-dev

npx eslint --init

180 of 191

Application démo

Code de l’application démo avec les différents exemples du cours : https://github.com/thibaultrive/react-demo

180

2025

181 of 191

La gestion de contenu

2025

182 of 191

Gatsby

182

2025

183 of 191

Les tests

2025

184 of 191

Les tests

Jest

184

2025

185 of 191

185

2025

186 of 191

186

2025

187 of 191

Tests & QA

187

2025

188 of 191

Accessibilité - a11y

eslint-plugin-jsx-a11y

188

2025

189 of 191

Génération contenu statique

189

2025

190 of 191

Gestion des erreurs

throw

190

2025

191 of 191

https://github.com/chenglou/react-motion

191

2025