Introduction au développement Web avec React JS
2025
Introduction
2025
Introduction - nombreux framework web
3
2025
Introduction - nombreux framework web
4
2025
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
Introduction - pourquoi React ?
6
2025
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
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
Introduction - librairie
Avantages de la librairie :
=> Très intéressant pour refondre progressivement un site web
9
2025
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
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
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
SPA, DOM & composants
2025
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
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
SPA – Single Page Application
Faire attention :
Risques : applications longues à charger (page blanche ou partiellement chargée), site qui lag ou freeze
16
2025
SPA – Single Page Application
Solutions :
17
2025
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
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
DOM - Document Object Model
Solution n°1 : le Shadow DOM
20
2025
DOM - Document Object Model
Solution n°2 : le Virtual DOM
21
2025
DOM - Document Object Model
22
2025
Composants
Approche composant -> découper la page Web en modules les plus petit possible
Chaque composant a :
Ex checkbox : (dé)cochée, ☑, sélection donnée associée
23
2025
Composants
Avantages :
24
2025
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
Composants
Et React dans tout ça ?
React facilite la création de composants en synchronisant automatiquement l’affichage avec l’état.
26
2025
Mon 1er composant
2025
1er composant - Choisir un IDE
Webstorm ou IDEA (licences étudiant)
N’importe quel éditeur de texte (vi, emacs, ...)
IDE en ligne pour tester au fil du cours (https://codesandbox.io/ ou autre)
28
2025
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
1er composant - installer node et npm
30
2025
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
1er composant - création de l’app
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
2025
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
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>
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
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>
);
}
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
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
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
🍌
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
41
2025
Les dépendances
2025
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"
}
Les dépendances
Version : [major].[minor].[patch]
Les versions peuvent être :
Autorise les versions patch supérieures ou les versions mineures si seul le major est spécifié
Autorise les màj qui ne modifient pas le digit non nul le plus à gauche
44
2025
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"
}
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
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')
);
Les dépendances
Et on obtient une app avec un barre de navigation material design sans faire de css
48
2025
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";
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";
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
Créer un composant
2025
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 !'
);
JSX
54
2025
3 façons d’instancier un composant
A n’utiliser que pour le composant racine.
55
2025
import ReactDOM from 'react-dom';
ReactDOM.render(
<div>Mon composant</div>,
document.getElementById('root')
);
3 façons d’instancier un composant
2) Composant fonctionnel
56
2025
export function App() {
return (
<div>Mon composant</div>
);
}
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>
);
}
}
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>
);
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
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>
);
❌
✅
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>
</>
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 }
</>);
Les fonctions
⚠️ Attention à la syntaxe :
63
2025
onClick={increment}
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);
}
❌
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
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>
👍
👎
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()}
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});
}
Le state
🚨 En React, le state est immutable
69
2025
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++;
}
❌
Le state est immutable
=> Il faut utiliser la fonction setter retournée par useState() pour indiquer à React de modifier le state.
71
2025
Les fonctions
Victoire
72
2025
Les hooks
2025
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
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]);
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
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
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
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
Rendu du composant
2025
Rendu du composant
Composant simple avec affichage d’une variable
81
2025
return (
<div>
<button onClick={handleClick}>Push Me</button> : {compteur}
</div>
);
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}
...
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)}
...
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>
);
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
Les props
2025
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
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}/>
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 (
<>...</>
)
}
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;
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
Les props
🚨 comme le state, les props sont en lecture seule
92
2025
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
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
}));
Les formulaires
2025
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 :
4) <form> : https://react.dev/reference/react-dom/components/form
96
2025
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);
}
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);
}
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);
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);
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" />
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
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}
}
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}>
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>
);
}
Appels API
2025
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});
}
)
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" }
})
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
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
Appels API
La partie API est généralement constituée :
Les frameworks les plus courants sont NestJS et Express.
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
Appels API
Pour utiliser les variables d’environnement :
Ex : REACT_APP_QUOTES_API_URL=http://api.quotable.io/random
🚨 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
Gestion des données
2025
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
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
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
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>
);
}
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
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()
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
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"
}
Gestion des données - Redux
122
2025
Gestion des données - Redux
Redux se base sur l’architecture “Flux” mise au point par Facebook
123
2025
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
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
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",
}
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
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;
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)
})
},
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,
},
});
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>
);
}
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>
);
}
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
Gestion des données - Redux
134
2025
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
Gestion des données
136
2025
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
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 }),
}))
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
}
});
Gestion des données
140
2025
const myData = useRecoilValue(asyncDataState);
const [counter, setCounter] = useRecoilState('counter');
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.
🚨 Attention au stockage d’informations sensibles (jwt, token) car elles seraient accessibles par tous les scripts Js de la page.
141
2025
Le routage
2025
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
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>
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>
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>
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>
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}
);
}
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>
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
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
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
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>
Le rendering
2025
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
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
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
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 :
158
2025
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>
SEO
Depuis la version 19, React supporte nativement les balises <title>, <link> et <meta> dans les composants.
160
2025
Le rendering
2 approches s’opposent pour générer le rendu des pages web :
161
2025
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
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
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
Optimisations - Static Rendering
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/>);
}
Microfrontend
2025
Microfrontend
Lorsqu’une application Web devient trop volumineuse, la gestion peut vite devenir laborieuse :
=> découper le site web en plusieurs morceaux
167
2025
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 :
Inconvénients :
168
2025
Microfrontend - reverse proxy
Utiliser un reverse proxy type NGINX pour rediriger les paths vers différentes applications
Avantages :
Inconvénients :
169
2025
Microfrontend - librairies
Avoir une application ”socle”, qui importe des vues définies dans plusieurs libs
Avantages :
Inconvénients :
170
2025
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
Les styles
2025
Les styles
3 façons de définir les styles :
173
2025
Les styles
3 façons de définir les styles :
Il est également possible d’utiliser des pre-processeur CSS comme SASS ou des framework CSS tels que tailwindcss.
174
2025
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}>
Le linter
2025
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 !
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"]
}
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
Application démo
Code de l’application démo avec les différents exemples du cours : https://github.com/thibaultrive/react-demo
180
2025
La gestion de contenu
2025
Gatsby
182
2025
Les tests
2025
Les tests
Jest
184
2025
185
2025
186
2025
Tests & QA
187
2025
Accessibilité - a11y
eslint-plugin-jsx-a11y
188
2025
Génération contenu statique
189
2025
Gestion des erreurs
throw
190
2025
https://github.com/chenglou/react-motion
191
2025