REACT
A FAIRE
- NODEJS Comment installer plusieurs versions sur un système
INTRODUCTION
A quoi sert React
ReactJS est une bibliothèque JavaScript open-source et gratuite développée par Facebook, utilisée pour construire des interfaces utilisateurs dynamiques et interactives.
ReactJS est utilisé pour le front-end.
ReactJS est conçu pour simplifier le développement d’applications web interactives.
- le virtual Dom
- parce qu’on écrit pas les commandes d’accès au DOM. On écrit directement dans le HTML avec JSX.
React utilise un DOM virtuel pour optimiser le rendu des éléments sur la page et rend l’affichage des modifications des éléments de la page plus rapides. Plutôt que de mettre à jour directement le DOM réel (ce qui est coûteux), React met à jour d’abord une version virtuelle et synchronise les changements nécessaires, rendant les applications plus rapides.
De plus les commandes de modifications en Javacript sont longues (par ex : Document.getElementsByClassName). C’est une des raisons pour lesquelles des bibliothèques de commandes ont été créées, comme la plus populaire qui a été jQuery.
Philosophie de React
React repose sur une philosophie fondamentale qui définit sa conception et son fonctionnement. Cette philosophie a été soigneusement pensée pour offrir une expérience de développement fluide, favoriser la réutilisabilité du code et améliorer les performances des applications web. Dans cette section, nous explorerons les principes-clés qui font la puissance de React.
a. Composants : l’unité de base
Ce sont les éléments fondamentaux qui définissent l’interface utilisateur. Chaque composant encapsule à la fois la logique et la vue de sa partie spécifique de l’interface. Cette approche modulaire permet de diviser une application en blocs réutilisables.
L’utilisation de composants rend également le code plus lisible et compréhensible, car chaque composant est une abstraction autonome qui peut être aisément manipulée et testée indépendamment. Les composants peuvent être imbriqués les uns dans les autres pour former des interfaces complexes, favorisant ainsi une conception déclarative de l’interface utilisateur.
b. Réactivité : mise à jour efficace de l’interface utilisateur
Un autre principe essentiel de React est sa réactivité. Lorsque l’état d’un composant change, React met automatiquement à jour l’interface utilisateur pour refléter ces modifications. Avant de mettre à jour directement le DOM avec les méthodes proposées par le navigateur, React utilise le DOM virtuel.
Lorsqu’un composant doit être mis à jour, React compare cette version avec l’ancienne. En analysant les différences entre les deux versions, React détermine les changements réels à appliquer dans le DOM du navigateur, en minimisant ainsi les manipulations du DOM réel. Dans les faits, nous avons besoin d’une partie spécifique de React : ReactDOM.
c. Composition : assemblage de composants réutilisables
React encourage la composition plutôt que l’héritage. Cela signifie que plutôt que de chercher à hériter des fonctionnalités d’autres composants, nous devrions les assembler en utilisant des compositions.
Nous allons donc principalement assembler des composants et React ne se soucie pas de la manière dont nous allons découper notre code. Il y a tout de même des bonnes pratiques et nous allons les aborder dans les chapitres suivants.
d. Une approche déclarative
Au lieu de manipuler directement le DOM pour mettre à jour l’interface utilisateur, nous décrivons simplement le « quoi » et React se charge du « comment ».
En utilisant JSX, une syntaxe de balisage similaire à l’HTML, nous pouvons décrire la structure de l’interface utilisateur de manière déclarative. React prend ensuite en charge la création et la mise à jour du DOM en fonction des changements d’état.
Cette approche déclarative rend le code plus lisible, maintenable et prévisible. Elle facilite également la recherche d’erreurs et le débogage, car la logique et la vue sont clairement séparées.
Ce sont les principes fondamentaux de React qui guident sa conception et son fonctionnement. En mettant l’accent sur les composants, la réactivité, la composition et l’approche déclarative, React offre une démarche puissante et intuitive pour la création d’interfaces utilisateur.
Bibliothèques utilisées par React
React ne vient pas tout seul, il a besoin d’une plateforme et d’autre bibliothèques pour fonctionner
- Webpack est un outil de construction de modules JavaScript open-source. Il sert à regrouper les fichiers et les ressources d’une application (HTML, CSS, JavaScript, images, etc.) en un ou plusieurs fichiers optimisés pour le déploiement.
Il transforme également des fichiers SCSS ou TypeScript en CSS ou JavaScript standard. Et aussi : Minification (réduction de la taille des fichiers), Compression des images.
- Babel Transpile le JavaScript moderne (ES6+) en une version compatible avec les anciens navigateurs.
- ESLint Un outil de linting pour détecter et corriger automatiquement les erreurs et les mauvaises pratiques dans le code
- PostCSS Permet de transformer et d’optimiser le CSS avec des plugins comme Autoprefixer (ajout automatique de préfixes pour la compatibilité entre navigateurs).
- Environment Variables Prise en charge intégrée des fichiers .env pour gérer les variables d’environnement.
- Fast Refresh Fournit une expérience de rechargement rapide et fluide pendant le développement.
- Des modules à ajouter manuellement :
- React Router : Pour la gestion de la navigation.
- Redux ou Context API : Pour la gestion de l’état global.
- Axios ou Fetch API : Pour les requêtes HTTP.
Comment ça marche
DOM virtuel / state / props
Le DOM est la représentation d’une page web qui convertit les balise HTML, les styles et le contenu en noeuds qui peuvent être manipulés par JavaScript. Les commandes JavaScript modifie le DOM et donc ce qui est affiché à l’écran.
Les manipulations du DOM sont lentes car quand le DOM est modifié car le navigateur web regarde si la page doit être redessinée et ensuite il la redessine. Les ingénieurs de Facebook qui ont créé React on créé une couche entre le code écrit par le programmeur et le DOM : cette couche est appelée virtual DOM.
Voici la démarche :
- Lorsque vous utilisez ReactDOM.render() (ou une autre méthode comme createRoot dans React 18), un unique élément React racine est rendu. Cet élément représente le point d’entrée de votre application React, il contient une arborescence complexe de composants et d’autres éléments React. React prend un seul point d’entrée pour tout votre code React. Tout le code est imbriqué dans une structure hiérarchique sous un unique élément React racine. Chaque composant conserve son indépendance et sa logique propre, mais tous ces composants sont organisés sous cet élément racine.
ReactDOM.render(<App />, document.getElementById('root')); function App() { return ( <div> <Header /> => composant imbriqué dans <App /> qui est la racine <MainContent /> => composant imbriqué dans <App /> qui est la racine <Footer /> => composant imbriqué dans <App /> qui est la racine </div> ); }
- La méthode render de ReactDOM crée une représentation simplifiée et légère de cet élément React dans la mémoire RAM (c’est ce qu’on appelle le Virtual DOM). Le Virtual DOM est une copie simplifiée utilisée pour effectuer les calculs en mémoire avant de synchroniser les changements nécessaires avec le DOM réel.
React crée une première version du Virtual DOM en mémoire, basée sur les composants React définis par le développeur.- RAM dans un ordinateur : La RAM est connectée à la carte mère via les slots RAM. Les barrettes de RAM sont des circuits imprimés rectangulaires avec des puces mémoire.
- RAM dans un smartphone : combinée avec d’autres composants (comme le processeur) dans une puce appelée SoC (System-on-a-Chip)
- ReactDOM écoute les événements nécessitant des modifications sur la page web.
- La méthode ReactDOM.render crée une nouvelle représentation en mémoire de la page web. Lorsqu’un état ou des propriétés changent dans un composant, une nouvelle version du Virtual DOM est générée en mémoire.
- La bibliothèque ReactDOM compare la nouvelle représentation du Virtual DOM de la page web avec la représentation précédente du Virtual DOM et calcule la différence entre les deux. Ce processus est appelé réconciliation.
- Une fois les différences calculées, React met à jour uniquement les parties nécessaires du DOM réel en fonction des résultats..
Div root : div id root = a regarder dans le HTML avec l’inspecteur
fichier index.js
- les composants que nous créons sont ajoutés dans le DOM grâce à la méthode createRoot
- StrictMode : sert à afficher les erreurs en cas de problème pour la phase de développement
import React from 'react';
import ReactDOM from 'react-dom/client'; // librairie qui permet de brancher react au DOM
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
Comparaison avec et sans React :
Comment fonctionne le DOM sans React ?
- Le DOM (Document Object Model) est une représentation en arbre de la structure HTML de la page.
- Lorsqu’une modification est apportée au DOM via JavaScript (par exemple avec
document.getElementById()
ouinnerHTML
), cette modification affecte directement la structure réelle du DOM.
- Si vous modifiez un élément, seul cet élément est modifié. Le DOM entier n’est pas mis à jour.
Exemple de mise à jour manuelle du DOM :
document.getElementById('myDiv').innerText = 'Nouveau texte';
Dans cet exemple, seul le contenu de l’élément avec l’ID myDiv est modifié, pas tout le DOM.
Cependant :
- Les interactions fréquentes avec le DOM peuvent devenir coûteuses en termes de performance, surtout si vous manipulez de nombreux éléments ou effectuez des mises à jour complexes.
- Les changements multiples doivent être soigneusement suivis et optimisés manuellement
Problème avec le DOM sans framework
- Manipulations complexes :
- Lorsque l’interface utilisateur devient complexe (par exemple, une liste d’éléments ou une interface interactive), suivre les parties exactes du DOM à mettre à jour peut devenir difficile et sujet à erreurs.
- Redondance :
- Vous risquez de mettre à jour des parties du DOM qui n’ont pas réellement changé, ce qui gaspille des ressources.
- Performances limitées :
- Les interactions directes avec le DOM sont relativement lentes, car le DOM est une interface puissante mais lourde.
- Par exemple, chaque mise à jour du DOM réel peut entraîner un recalcul du style et un re-rendering visuel par le navigateur.
- Comment React optimise ce processus ?
- Virtual DOM :
- React crée une copie légère et simplifiée du DOM réel en mémoire (le Virtual DOM).
- Lorsqu’une mise à jour se produit, React met à jour cette copie, puis compare la nouvelle version avec l’ancienne (processus appelé réconciliation).
- Seules les différences entre les deux versions sont calculées et appliquées au DOM réel.
- Virtual DOM :
- Mises à jour minimales :
- React applique uniquement les changements nécessaires au DOM réel, réduisant ainsi le nombre d’interactions directes avec le DOM.
Sans un mécanisme comme le Virtual DOM, le développeur doit gérer les optimisations manuellement, ce qui est plus complexe et moins efficace pour des applications complexes
- Comparaison automatique : React compare l’ancien état du Virtual DOM avec le nouvel état pour détecter les changements nécessaires.
- Batching des mises à jour : React regroupe les mises à jour pour optimiser leur application au DOM réel.
- Abstraction du DOM réel : Le développeur n’a pas besoin de manipuler directement le DOM. React s’en occupe, ce qui réduit les erreurs et améliore les performances.
L’accès au DOM avec REACT
Avec React, vous n’avez presque jamais besoin d’utiliser directement des méthodes DOM comme document.getElementById() pour manipuler ou accéder aux éléments HTML. React fournit une manière plus déclarative et organisée de gérer les composants et les éléments via son système de Virtual DOM et de props/state.
Comment accéder au DOM en React ? (Avec refs)
Cependant, il existe des cas spécifiques où vous pourriez avoir besoin d’accéder directement à un élément du DOM, et React propose une manière contrôlée de le faire avec les refs.
React fournit les refs (références) pour accéder directement à un élément DOM. Les refs permettent de créer une liaison contrôlée entre React et un élément DOM spécifique, sans utiliser document.getElementById().
import React, { useRef } from 'react';
function App() {
const myDivRef = useRef(null); // Crée une référence à l’élément DOM.
const handleClick = () => {
console.log(myDivRef.current); // Accède à l'élément DOM
myDivRef.current.style.backgroundColor = 'yellow'; // Modifie le style directement / Accède directement à l’élément DOM réel, comme avec document.getElementById().
};
return (
<div>
<div ref={myDivRef} style={{ width: '200px', height: '100px', background: 'blue' }}> // Associe cette référence à l’élément DOM que vous voulez contrôler.
Je suis un div
</div>
<button onClick={handleClick}>Changer la couleur</button>
</div>
);
}
export default App;
Pour ne pas utiliser de DOM on utilise les state et les props
STATE
Dans cet exemple, vous n’avez pas besoin de document.getElementById() pour mettre à jour le texte du compteur. React met automatiquement à jour le DOM lorsque le state (count) change.
import React, { useState } from 'react';
function App() {
const [count, setCount] = useState(0);
return (
<div>
<p>Le compteur est : {count}</p>
<button onClick={() => setCount(count + 1)}>Incrémenter</button>
</div>
);
}
export default App;
PROPS
Les props (abréviation de “properties”) sont des paramètres passés d’un composant parent à un composant enfant. Elles permettent de transmettre des données ou des fonctions pour personnaliser le comportement ou l’affichage d’un composant.
import React from 'react';
function App() {
return (
<div>
<UserCard name="Alice" age={25} />
<UserCard name="Bob" age={30} />
</div>
);
}
function UserCard(props) {
return (
<div style={{ border: '1px solid black', margin: '10px', padding: '10px' }}>
<h2>Nom : {props.name}</h2>
<p>Âge : {props.age} ans</p>
</div>
);
}
export default App;
// Résultat affiché :
Nom : Alice
Âge : 25 ans
Nom : Bob
Âge : 30 ans
Cela permet d’utiliser la fonction UserCard dans plusieurs parties de l’application ou du site sans avoir à l’écrire plusieurs fois.
Cela rend donne à votre code :
- Réutilisabilité
- Simplification et lisibilité
- Facilité de maintenance
- Modularité et évolutivité
RESSOURCES
- Les fichiers de codes sont stockés ici : https://github.com/julliechaumard/react_course
- Livres
- “ReactJS Foundations Building User Interfaces with ReactJS” de Chris Minnick
- “Maîtrisez React en 5 jours” de Éric Sarrion
- “React Développez le Front End de vos applications web et mobiles avec JavaScript” de Hakim Madani
INSTALLATION
Environnement nodejs
Comment installer plusieurs versions sur un système
React Developer Tools (Chrome)
Outils de développement React (React Developer Tools)
Pour aider les développeurs à déboguer les applications React, Facebook a créé une extension de navigateur appelée React Developer Tools. Cette extension est actuellement disponible uniquement pour Chrome et Firefox. Une fois installée, elle ajoute deux nouveaux onglets dans les outils de développement du navigateur : Components et Profiler.
Voici comment l’installer et l’utiliser.
Installation des React Developer Tools
Sur Chrome :
- Ouvrez votre navigateur Chrome et rendez-vous sur le Chrome Web Store : https://chrome.google.com/webstore.
- Recherchez React Developer Tools dans la barre de recherche.
- Dans les résultats, sélectionnez l'extension React Developer Tools développée par Facebook.
- Cliquez sur le bouton Ajouter à Chrome. L’extension sera installée dans votre navigateur.
Premiers pas avec React Developer Tools
- Ouvrez les Chrome DevTools
- Si la page que vous visualisez n'utilise pas React, vous ne verrez aucun changement dans les outils.
- Rendez-vous sur https://reactjs.org dans votre navigateur.
- Les onglets Components et Profiler apparaîtront dans les outils de développement.
- Cliquez sur l’onglet Components :
- Vous verrez une vue en arborescence des composants React utilisés pour créer l'interface utilisateur.
Comprendre la vue Components
- Chaque élément affiché dans l'onglet Components représente un composant React de l'application.
- Composants en production vs en développement :
- Dans les applications React en production :
- Les noms des composants sont minifiés pour réduire la taille du fichier.
- La plupart des fonctionnalités de débogage sont désactivées pour améliorer les performances.
- Les outils React Developer Tools fonctionnent mieux avec les versions de développement de React, car elles incluent des noms lisibles et toutes les options de débogage.
- Dans les applications React en production :
Exploration et utilisation de React Developer Tools
- Navigation dans les composants :
- Cliquez sur un composant dans la vue Components pour voir ses props, son state, et d'autres informations.
- Utilisez l'outil d’inspection d’éléments (icône en haut à gauche) pour mettre en évidence les composants React directement dans la page.
- Différence avec l'inspecteur d'éléments du navigateur :
- L’inspecteur d’éléments du navigateur montre le HTML et les styles du DOM dans le navigateur.
- L’inspecteur des React Developer Tools montre les composants React qui ont produit ces nœuds DOM.
- Vue d'ensemble :
- Pensez à l’onglet Components comme une vue de haut niveau des composants React, tandis que l’inspecteur du navigateur se concentre sur les éléments HTML finaux.
Le Profiler : Analyse des performances
- Fonctionnalité :
- L'onglet Profiler fournit des informations sur les performances de votre application React.
- Il montre comment chaque composant React a été rendu et combien de temps cela a pris.
- Utile pour optimiser les applications React.
- Limitation :
- Le profiling est désactivé dans la version de production de React. Cela signifie que cet onglet ne sera pas fonctionnel lorsque vous visiterez une page publique utilisant React.
VSC
Pour travailler efficacement avec React dans Visual Studio Code, plusieurs extensions peuvent grandement améliorer votre expérience de développement. Voici une liste des extensions incontournables pour React :
1. ES7+ React/Redux/React-Native Snippets
📌 Description :
- Fournit des snippets de code pour React, Redux et React-Native.
- Vous pouvez générer rapidement des composants, des hooks, ou des fonctions avec des raccourcis.
- Exemple : Tapez rafce pour générer un composant fonctionnel avec export.
Installation : Recherchez ES7+ React/Redux/React-Native Snippets dans le Marketplace.
Lien : ES7+ Snippets
2. React Developer Tools
📌 Description :
- Intégration de React DevTools directement dans VS Code.
- Permet de déboguer et d’inspecter l’arbre des composants React.
Installation : Recherchez React Developer Tools dans le Marketplace.
Lien : React Developer Tools
3. Prettier - Code Formatter
📌 Description :
- Formate automatiquement votre code React pour le rendre propre et lisible.
- Compatible avec JSX, CSS-in-JS, et autres fichiers liés à React.
Installation : Recherchez Prettier - Code Formatter.
Lien : Prettier
4. ESLint
📌 Description :
- Analyse le code pour détecter des erreurs de syntaxe ou des mauvaises pratiques.
- Fonctionne parfaitement avec React et aide à maintenir un code de haute qualité.
Installation : Recherchez ESLint.
Lien : ESLint
5. React PropTypes Intellisense
📌 Description :
- Ajoute l’autocomplétion et les suggestions pour les propriétés d’un composant React basé sur ses PropTypes.
Installation : Recherchez React PropTypes Intellisense.
Lien : React PropTypes Intellisense
6. Auto Rename Tag
📌 Description :
- Modifie automatiquement l’étiquette fermante d’un élément JSX si vous changez l’étiquette ouvrante.
Installation : Recherchez Auto Rename Tag.
Lien : Auto Rename Tag
7. Bracket Pair Colorizer
📌 Description :
- Colore les paires d’accolades et de parenthèses pour faciliter la lecture et la compréhension du JSX imbriqué.
Installation : Recherchez Bracket Pair Colorizer.
Lien : Bracket Pair Colorizer
8. Code Spell Checker
📌 Description :
- Vérifie l’orthographe dans les fichiers JSX, utile pour éviter les fautes dans les noms de variables, commentaires ou textes.
Installation : Recherchez Code Spell Checker.
Lien : Code Spell Checker
11. Path IntelliSense
📌 Description :
- Fournit l’autocomplétion pour les chemins d’importation dans vos fichiers React.
Installation : Recherchez Path IntelliSense.
Lien : Path IntelliSense
Installer React au démarrage du projet
Créer une appli avec create-react-app
Create React App (CRA), un outil qui configure automatiquement une application React avec Webpack, Babel, et d’autres outils modernes.
npx create-react-app react_app_test
ou pour spécifier la version de React à installer :npx create-react-app react_app_test --template cra-template --use-npm --react 18
- ou bien si erreur de dépendance :
npx create-react-app react_app_test --use-npm --template cra-template
- aller dans le dossier du projet créé puis :
npm uninstall react react-dom
npm install react@18 react-dom@18
- Si dans le fichier
package.json
on ne voit pas la dépendance “web-vitals” dans la partie “dependencies” il faut l’installer manuellement :npm install web-vitals
- Démarrer l’appli :
- aller dans le dossier du projet créé puis :
npm start
- aller dans le dossier du projet créé puis :
Voir version installée
Dans le fichier package.json
ou bien avec la commande npm list react
Démarrer l’application REACT
- Aller dans le dossier du projet créé puis :
npm start
Modifier id=”root”
Dans le fichier react_app_test/public/index.html
// remplacer
<div id="root"></div>
// par
<div id="couleur"></div>
Dans le fichier react_app_test/src/index.js
// remplacer
const root = ReactDOM.createRoot(document.getElementById('root'));
//par
const root = ReactDOM.createRoot(document.getElementById('couleur'));
Message de l’auteur
📚Voir cours “Programmation” chapitre “Légalité”
Dans le fichier react_app_test/public/index.html
<html lang="fr">
<!--
Vous regardez dans mon code ;) N'hésitez pas à communiquer avec moi pour discuter du codage, webdesign... ;)
-- julie at parisweb.art -- ou juliechaumard sur Linkedin
A bientôt !
Testé sur les navigrateurs
Firefox, Safari, Chrome
-->
<head>
Installer React dans un projet existant
Un projet NodeJS sans EJS ni express
Pour installer React dans un projet existant, voici les étapes à suivre :
1. Installer React et ReactDOM
Dans le dossier de votre projet, exécutez la commande :
npm install react react-dom
2. Installer Babel et Webpack (si nécessaire)
Si vous utilisez Webpack, installez les dépendances pour compiler React :
npm install --save-dev webpack webpack-cli webpack-dev-server babel-loader @babel/core @babel/preset-env @babel/preset-react html-webpack-plugin
Ajoutez un fichier .babelrc :
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
3. Configurer Webpack (si nécessaire)
Créez un fichier webpack.config.js :
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
devServer: {
static: './dist',
},
};
4. Ajouter un fichier index.js
Dans src/index.js, ajoutez un exemple React :
import React from 'react';
import ReactDOM from 'react-dom';
const App = () => <h1>Hello React!</h1>;
ReactDOM.render(<App />, document.getElementById('root'));
5. Ajouter un fichier index.html
Dans public/index.html :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
6. Démarrer le projet
Ajoutez un script dans package.json :
"scripts": {
"start": "webpack serve --mode development",
"build": "webpack --mode production"
}
Puis lancez :
npm start
Un projet NodeJS avec EJS et express
1. Installer React et ses dépendances
Dans votre projet Express existant, installez React et ReactDOM :
npm install react react-dom
Installez aussi Babel et Webpack pour transpiler le code React :
npm install --save-dev webpack webpack-cli webpack-dev-server babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/plugin-transform-runtime
2. Configurer Babel
Ajoutez un fichier .babelrc à la racine du projet :
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": ["@babel/plugin-transform-runtime"]
}
3. Configurer Webpack
Créez un fichier webpack.config.js :
const path = require('path');
module.exports = {
entry: './client/index.js',
output: {
path: path.resolve(__dirname, 'public'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
],
},
resolve: {
extensions: ['.js', '.jsx'],
},
mode: 'development',
};
4. Créer le fichier React principal
Dans client/index.js, créez un composant React :
import React from 'react';
import ReactDOM from 'react-dom';
const App = () => {
return <h1>Hello from React in Express + EJS!</h1>;
};
ReactDOM.render(<App />, document.getElementById('root'));
5. Modifier le fichier EJS pour inclure React
Dans votre fichier views/index.ejs (ou autre template EJS), ajoutez :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Express + React</title>
</head>
<body>
<div id="root"></div>
<script src="/bundle.js"></script>
</body>
</html>
6. Modifier le serveur Express pour servir les fichiers
Dans votre fichier server.js ou app.js, ajoutez :
const express = require('express');
const path = require('path');
const app = express();
// Définir EJS comme moteur de rendu
app.set('view engine', 'ejs');
// Servir les fichiers statiques (dont le bundle React)
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', (req, res) => {
res.render('index'); // Rendu du fichier EJS qui inclut React
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Serveur démarré sur http://localhost:${PORT}`);
});
7. Compiler et démarrer le projet
Ajoutez ces scripts dans package.json :
"scripts": {
"build": "webpack",
"start": "node server.js",
"dev": "webpack --watch & nodemon server.js"
}
Puis exécutez les commandes suivantes :
1. Compiler React :
npm run build
2. Démarrer le serveur Express :
npm start
Installer SCSS
Dans le dossier du projet
npm install sass --save-dev
AJOUTER LE CSS
- créer une arborescence vierge de fichier react et css
ARCHITECTURE / STRUCTURER / COMMENTAIRES
- Reprendre l’architecture du codage du projet
- Modularité : Vous pouvez gérer les modules séparément, ce qui facilite leur mise à jour ou leur extension.
- Scalabilité : Dans une application complexe avec de nombreuses routes et modules, structurer permet de mieux gérer leur organisation.
- Réutilisabilité : vous pouvez réutiliser les composants.
Architecture des fichiers
Exemple de structure typique d’un projet React
src/
├── components/ # Contient les composants React
├── hooks/ # Contient les hooks personnalisés
│ ├── useAuth.js # Exemple : gestion de l'authentification
│ ├── useFetch.js # Exemple : abstrait les appels API
│ ├── useForm.js # Exemple : gestion des formulaires
│ ├── useTheme.js # Exemple : gestion des thèmes
├── pages/ # Composants spécifiques à une page
├── utils/ # Fonctions utilitaires réutilisables
├── services/ # Appels API ou logique de backend
└── App.jsx # Point d'entrée principal
Nous allons réorganiser les fichiers de code pour créer des fichiers par composants pour rendre le projet plus modulaire.
Reprenons la page Home.js
src/
├── hooks/
│ ├── usePersonName.js
│ ├── useColor.js
│ ├── useBoxes.js
├── components/
│ ├── Bonjour.jsx
│ ├── FormCouleur.jsx
│ ├── FormPrenom.jsx
│ ├── CarreList.jsx
│ ├── AjouterCarre.jsx
├── Home.jsx
Structurer le code :
- Déclarations des variables et des constantes
- Placez les variables ou constantes nécessaires pour le composant en haut de la fonction
- Cela inclut les variables locales, les destructurations des props, et les calculs initiaux.
- Déclarations des hooks React
- Placez les hooks comme useState, useEffect, et autres après les variables.
- Ces hooks doivent être définis dans le corps principal du composant et dans le même ordre à chaque rendu, conformément aux règles des hooks.
- Fonctions utilitaires ou internes
- Déclarez les fonctions utilisées dans le composant (ex. : gestionnaires d’événements, transformations de données, etc.).
- Placez-les après les hooks, mais avant le return.
- Contenu HTML/JSX
- Le contenu JSX que le composant retourne doit être placé à la fin dans la section return.
Commenter le code :
- expliquer ce que font les instructions et que sont les variables
JAVASCRIPT
Quelques rappels
Export d’une fonction
- On peut utiliser export default
Header
et ne pas mettre d’accolades dans l’import (”default” veut dire qu’il n’y a qu’une seule fonction à exporter dans le module.
- ou bien si on a plusieurs fonctions à exporter dans un fichiers on met des accolades comme ceci et on ne met pas “default”, mais on créé des exportations nommées.
La fonction enfant : export {Header};
import React from 'react';
import { Link } from 'react-router-dom';
function Header() {
let headerContent;
headerContent = (
<header>
<h1>En-tête du site</h1>
<nav>
<ul>
<li><Link to="/">Accueil</Link></li>
<li><Link to="/mentions-legales">Mentions légales</Link></li>
</ul>
</nav>
</header>
);
return headerContent;
}
export {Header};
L’appel de la fonction : import {Header} from './components/Header';
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import AppRoutes from './routes/AppRoutes'; // Import des routes
import {Header} from './components/Header';
import Footer from './components/Footer';
import './App.css';
import './scss/app.scss';
function App() {
return (
<Router>
<Header /> {/* En-tête commun à toutes les pages */}
<AppRoutes /> {/* AppRoutes est utilisé pour organiser et gérer toutes les routes (les associations entre les chemins URL et les composants à afficher) de l’application */}
<Footer /> {/* Pied de page commun */}
</Router>
);
}
export default App;
On importe React sans crochet car React n’est pas une exportation nommée.
import React, { useEffect, Fragment} from 'react';
COMPOSANT
Un composant en React est une brique de base réutilisable pour construire l’interface utilisateur d’une application. Un composant peut être vu comme une fonction ou une classe qui renvoie une partie de l’interface utilisateur (UI), définie avec du HTML, du JavaScript et, souvent, du CSS.
C’est une fonction JavaScript ou une classe qui renvoie du JSX (JavaScript XML), un mélange de JavaScript et de HTML.
Voici un composant qui est stocké dans un fichier avec seulement son code pour pouvoir le réutiliser ailleurs dans le projet (modularité)
function Bonjour({ name }) {
return <h1>Bonjour, {name} !</h1>;
}
Voici comment on l’appelle : (on peut voir une propriété qui est passé au composant (name="Alice"
), c’est ce qu’on appelle les props.
<Bonjour name="Alice" />
JSX
Le code JSX dans React est une syntaxe qui permet d’écrire des éléments d’interface utilisateur en comibanat JS et HTML de manière lisible et plus facile.
Le code JSX est composé de balise HTML.
Pour écrire du code JS dans ce JSX on met le JS entre accolades.
- conversion en JavaScript : Dans l’inspecteur Chrome, partie réseau, on regarde le fichier .jsx ou .js. On voit la conversion en JavaScript
- conversion en HTML/css : comme dans le HTML, si on écrit la propriété classe name en React, on voit bien que cela se transforme en classe dans le navigateur via l' inspecteur
- balise racine : Dans un composant il ne faut qu'une seule balise racine, qui imbrique les autres balise
- Ici, la balise racine qui englobe les autres balises est <div>
function App() { return <div> <h1 id="title" className="roug">Bonjour</h1> <p> Ceci est un paragraphe </p> </div> } export {App}
- si on ne veut pas ajouter d’élément racine, comme une div, dans le composant, on crée un fragment. il faut ajouter la biblio fragment.
import {Fragment} from "react"; function App() { return <Fragment> <h1 id="title" className="roug">Bonjour</h1> <p> Ceci est un paragraphe </p> </Fragment> } export {App}
- ou bien une balise ouvrante et fermante sans rien, juste les chevrons.
function App() { return <> <h1 id="title" className="roug">Bonjour</h1> <p> Ceci est un paragraphe </p> </> } export {App}
- balise fermentes : Toutes les balises doivent avoir une balise fermée, même celle qui ne sont pas fermantes dans HTML (comme par exemple la balise input) avec une balise fermant ou auto fermante.
- variable : On peut mettre des variables partout dans le code JSX, autant dans le contenu des balises que dans les propriétés des className. On note les variables avec des accolades :
{nomVariable}
- Événement (interactivité) :
- Clic sur un élément pour provoquer quelque chose :
- Fonction qui va gérer l’événement et qui prend en paramètre l’événement (
handleClick = (e) => {
) qui sera “traduit” en événement React, ce qui permet d’avoir une seule façon de “coder” même si on est dans un autre environnement comme le mobile.
- on met le listener dans le HTML (onClick). On pourra voir le listenner et l’événement dans l’inspecteur de Chrome dans Elements/Event Listeners
const title = "Bonjour" function App() { // fonction qui va gérer l'événement const handleClick = (e) => { alert("J'ai cliqué sur le titre") } return <div> <h1 onClick={handleClick} id="title" className="roug">{title}</h1> <input type="text"/> <p> Ceci est un paragraphe </p> </div> } export {App}
- Fonction qui va gérer l’événement et qui prend en paramètre l’événement (
- Clic sur un élément pour provoquer quelque chose :
- Condition :
avec une condition ternaire
const title = "Bonjour" const showTitle = false function App() { return <div> { showTitle ? <h1 onClick={handleClick} id="title" className="roug">{title}</h1> : <p>demo</p> } <input type="text"/> <p> Ceci est un paragraphe </p> </div> } export {App}
autre manière d’écrire la condition :
1. {showTitle && ...} :
• C’est une expression JSX qui utilise l’opérateur logique && (ET logique).
• Le && fonctionne de manière à évaluer l’expression à droite seulement si l’expression à gauche est true.
• Si showTitle est true, alors le <h1> sera affiché. Sinon, rien ne sera rendu.
const title = "Bonjour" const showTitle = false function App() { return <div> {showTitle && <h1 onClick={handleClick} id="title" className="roug">{title}</h1>} <input type="text"/> <p> Ceci est un paragraphe </p> </div> } export {App}
- Organiser les composants et créer des composants personnalisés :
- On créé une fonction pour afficher le titre. On pourra se servir de cette fonction dans plusieurs endroits de code et des pages
- on peut mettre la fonction dans un fichier pour l’appeler dans plusieurs fichiers du codes
- on peut ajouter des attributs personnalisés sous forme d’objet en paramètre de la fonction
- par exemple :
color="red"
- par exemple :
- la fonction reçoit tous les paramètres avec le mot clé “
props
”
- Il faut définir le contenu de props des variables locales. Ces valeurs doivent être extraites de props. Avec
const { color } = props;
const title = "Bonjour" const showTitle = false function App() { function Title (props) { console.log(props) const { color } = props; // déclaration des variables locales return <h1 style={{color : color}}>Bonjour</h1> } return <div> <Title color="red"/> // appel de la fonction Title avec des paramètre <input type="text"/> <p> Ceci est un paragraphe </p> </div> } export {App}
- children : pour récupérer ce qui est dans la balise. Dans ce cas on ferme la balise.
const title = "Bonjour" const showTitle = false function App() { function Title (props) { console.log(props) // { color: "red", children: "Mon composant" } const { color, children } = props; return <h1 style={{color : color}}>{children}</h1> } return <div> <Title color="red">Mon composant</Title> // appel de la fonction Title avec des paramètre <input type="text"/> <p> Ceci est un paragraphe </p> </div> } export {App}
Le composant personnalisé () s’écrit avec une majuscule sur la première lettre
- attributs qui n’ont pas de valeur : hidden.
- si hidden est dans la propriété du composant
<Title color="red" hidden>
alors il sera àtrue
dans le props
const title = "Bonjour" const showTitle = false function App() { function Title (props) { console.log(props) // { color: "red", children: "Mon composant" } const { color, children, hidden } = props; if (hidden) { // hidden est à true car il est présent dans les propriétés du composant. return null } return <h1 style={{color : color}}>{children}</h1> } return <div> <Title color="red" hidden>Mon composant</Title> // appel de la fonction Title avec des paramètre <input type="text"/> <p> Ceci est un paragraphe </p> </div> } export {App}
- si hidden est dans la propriété du composant
hook
- Fonctions :
- qui commencent par le mot-clé use
- qui ne peuvent être utilisées qu’à l’intérieur des composants.
- Pour pouvoir utiliser cette fonction soit on l’importe, soit on l’appelle avec react au moment où on l’utilise
- import :
import React, {useState} from 'react';
- appel :
React.useState()
- import :
- on passe une valeur initiale au hook :
useState(8)
(si on passe la valeur 8)
- la fonction va nous retourner 2 éléments (2 éléments dans un tableau)
par exempleconst [count, setCount] = useState(8)
- élément 1 : la valeur (count)
- élément 2 : un “set” qui permettre de changer la valeur (setCount)
useState
Exemple : On demande à une personne de saisir son nom. Au fur et à mesure qu’elle écrit les lettres, les lettres écrites s’affichent à l’écran. Ici le changement d’état se produit dans le <input> de saisie à chaque saisie (sans qu’il est besoin de faire un bouton “valider” pour récupérer le contenu de l’input).
Home()
= c’est le composant
- ici le “set”
setPersonName
modifie la valeur depersonName
quand l'utilisateur modifie le champinput
texte.
onChange={handleInputChange}
: Appelle `handleInputChange` lorsque l'utilisateur tape.handleInputChange
va activer le “set”setPersonName
function Home() {
const [personName,setPersonName] = useState('');
const handleInputChange = (event) => {
setPersonName(event.target.value);
};
homeContent = (
<div className="bonjour">
{/* On a un champ texte et on écoute la modification de ce champ par l'utilisateur */}
<div className="formBonjour_prenom">
<input type="text" onChange={handleInputChange} placeholder="Entrer votre prénom"/>
</div>
{/* ici one affiche le champ personName mis à jour par le set (setPersonName) */}
<div>
<h1>Bonjour <span style={{ color: color }}>{personName}</span></h1>
</div>
</div>
);
return homeContent;
}
export default Home;
Dans notre exemple, nous allons utiliser une valeur qui contient un tableau avec 2 valeurs au lieu d’une simple valeur “nom”. Nous allons récupérer la saisie du nom toujours pareil, mais pour l’affichage au lieu de dire bonjour dans la balise <h1> nous allons définir une variable pour personnaliser cette salutation. Cette salutation sera donnée dans le fichier Home.js. Elle sera mise en variable dans le hook useState pour avoir la possibilité de la modifier plus tard si besoin. Donc maintenant on aura un tableau avec 2 valeurs, le texte de la salutation et le nom de la personne. Le hook ne va modifier dynamiquement que le texte de la personne puisque la salutation est donné dans le fichier Home.js.
- on peut mettre des objets comme valeurs dans le useState
- Pour la modification du tableau, attention en react un changement doit créer une nouvelle version complète de la données : on ne peut pas faire de mutation (prendre un élément et le changer directement comme
count++
, ou ajouter des éléments avec par exemplenumbers.push(4)
).
Ce qui veut dire, dans notre exemple, que l’on ne peut pas demander de modifier uniquement le nom, il faut récupérer le tableau en entier (avec les 2 valeurs salutation et nom) pour mettre à jour le nom. Pour faire cela on utilise la syntaxe…nomvaleur
qui est le spread operator (...numbers) qui crée un nouveau tableau en récupérant les valeurs initiales du tableau.
...personNamepersonalise
veut dire : “récupère toutes les propriétés de personName avant la modification
nom : event.target.value
: et change la valeur de nom
const [personName,setPersonName] = useState('');
const [personNamepersonalise,setPersonNamepersonalise] = useState({
salutation : 'Ave', nom : ''
});
const handleInputChange = (event) =>
//setPersonNamepersonalise(({nom : event.target.value})); // ne fonctionne pas car efface le contenu du tableau
setPersonNamepersonalise(() => ({...personNamepersonalise, nom : event.target.value}));
};
homeContent = (
<div className="bonjour">
<div className="formBonjour_prenom">
<input type="text" onChange={handleInputChange} placeholder="Entrer votre prénom"/>
</div>
<div>
<h1>Bonjour <span style={{ color: color }}>{personName}</span></h1>
<h1>{personNamepersonalise.salutation} <span style={{ color: color }}> {personNamepersonalise.nom}</span></h1>
</div>
</div>
);
return homeContent;
- un composant peut avoir plusieurs hook
- Reprendre le code du projet des couleurs et architecturer la page
Home.js
avec des fichiers distincts pour le template de la page(Home.js)
, le hook(usePerson.js)
et le composant(Bonjour.js)
- Attention les valeurs initiales sont données dans le template de la page d’accueil, et non dans le hook ou le composant, pour plus de modularité
- Création des 3 fichiers :
useEffect
useEffect
est un Hook de React qui permet d'exécuter du code après le rendu du composant. Il est utilisé pour gérer des effets de bord comme :
- Écouter des événements (scroll, resize, etc.)
- Récupérer des données (API)
- Manipuler le DOM
- Mettre à jour un état en fonction d'une dépendance
Syntaxe de base
useEffect(() => {
// Code exécuté après le rendu du composant
});
⚠ Problème : Si on l’utilise ainsi, il s'exécutera à chaque rendu, ce qui n'est pas optimal.
Syntaxe de useEffect
avec dépendances
useEffect(() => {
// Code à exécuter
}, [dépendances]);
Les dépendances sont les variables qui déclenchent l'exécution de useEffect
- Quand
dépendances
change, le code à l’intérieur deuseEffect()
est ré-exécuté.
- Si
dépendances
est vide[]
, l'effet ne s'exécute qu'une seule fois après le premier rendu.
Exemples d'utilisation :
✅ Exécuter du code une seule fois (au montage du composant)
Si on met un tableau vide []
comme dépendance, le useEffect
ne s’exécute qu’une seule fois (au componentDidMount
en React Classique).
useEffect(() => {
console.log("Composant monté !");
}, []); // [] = Exécuté une seule fois
💡 Utilisation typique : Charger des données depuis une API.
Exécution unique ([]
) pour une requête API
useEffect(() => {
fetch("https://api.example.com/data")
.then(response => response.json())
.then(data => console.log(data));
}, [])
Fait la requête API une seule fois après le premier rendu.
Différences entre JS Pur et Reac
JS Pur (fetch() ) | React (useEffect() ) | |
Quand la requête API s'exécute | Directement à l’appel de fetch() | Après le premier rendu du composant |
Se ré-exécute sur re-rendu ? | Oui (si mis dans une fonction appelée plusieurs fois) | Non (grâce à useEffect([], []) ) |
Gestion de l’état | Doit être géré manuellement | Utilisation de useState() pour stocker les données |
Utilisation idéale | Scripts simples, HTML statique | Composants dynamiques React |
✅ Exécuter du code à chaque fois qu'une variable change
Si on met une variable dans le tableau de dépendances, useEffect
s'exécutera à chaque changement de cette variable.
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`Le compteur est maintenant à ${count}`);
}, [count]); // Exécuté chaque fois que count change
💡 Utilisation typique : Mettre à jour une donnée quand une autre change.
- L'effet ne s'exécute que si
count
change.
- Si
count
ne change pas,useEffect
ne s'exécute pas.
✅ Exécuter un effet avec nettoyage (cleanup
)
Si l'effet ajoute un événement, il est important de le nettoyer pour éviter des problèmes de performance.
useEffect(() => {
const handleScroll = () => {
console.log("L'utilisateur fait défiler la page !");
};
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
💡 Pourquoi le return () => {...}
?
👉 Nettoie l'effet quand le composant est démonté pour éviter des fuites de mémoire.
🔴 Mauvaise utilisation : Sans tableau de dépendances
Si on ne met pas de tableau []
, useEffect
s'exécutera à chaque rendu, ce qui peut causer des ralentissements.
useEffect(() => {
console.log("Je me lance à chaque rendu !");
});
❌ À éviter si on ne veut pas de re-rendu infini.
Cas | Dépendance utilisée | Comportement |
---|---|---|
Sans dépendance | useEffect(() => { ... }); | ⚠ Exécuté à chaque rendu (peu performant) |
Avec un tableau vide [] | useEffect(() => { ... }, []); | ✅ Exécuté une seule fois après le premier rendu |
Avec une dépendance spécifique | useEffect(() => { ... }, [count]); | ✅ Exécuté uniquement quand count change |
Avec plusieurs dépendances | useEffect(() => { ... }, [count, name]); | ✅ Exécuté quand count ou name changent |
Avec un nettoyage (return ) | useEffect(() => { return () => { ... }; }, []); | ✅ Nettoie un événement/timer au démontage du composant |
useRef
useEffect
Exercice scroll horizontal
Un bloc où l’on scroll horizontalement pour faire défiler le contenu, ici des images. Les images qui n’apparaissent pas entièrement (ou à 90%) sont opacifié pour inciter l’internaute à avoir le geste du scroll pour aller voir.
On peut faire aussi un défilement horizontale avec uniquement du CSS, ou du CSS et du Javascript (si besoin de Drag Scroll)
Méthode | Avantages | Inconvénients |
---|---|---|
CSS uniquement (overflow-x ) | Simple, aucune dépendance | Pas d’interaction avancée |
JavaScript (Drag Scroll) | Expérience fluide, interactions | Un peu plus de code |
React (useRef + useEffect) | Composant réutilisable, gestion avancée | Plus complexe, dépendance React |
Explication du code
1️⃣ Affiche un slider horizontal d’images.
2️⃣ Détecte quelles images sont partiellement visibles (moins de 90%).
3️⃣ Applique une classe .faded
sur ces images pour ajouter une transparence progressive
4️⃣ Anime le défilement horizontal avec framer-motion
useState
→ Gère l’état des images partiellement visibles.
useRef
→ Référence le conteneur du défilement.
useEffect
→ Exécute du code lorsqu’un composant est monté (ici, pour gérer la détection de visibilité)
motion
(de framer-motion
) → Permet d’animer le conteneur.
import React, { useState, Fragment, useRef, useEffect } from "react";
import { motion } from "framer-motion";
Charge les 7 images depuis le dossier assets/images/
et les stocke dans un tableau images
.
import image1 from "./../assets/images/image1.webp";
import image2 from "./../assets/images/image2.webp";
import image3 from "./../assets/images/image3.webp";
import image4 from "./../assets/images/image4.webp";
import image5 from "./../assets/images/image5.webp";
import image6 from "./../assets/images/image6.webp";
import image7 from "./../assets/images/image7.webp";
const images = [
image1, image2, image3, image4, image5, image6, image7
];
Déclaration du composant Exercice5
function Exercice5() {
✅ scrollRef
:
- Stocke une référence vers le conteneur du défilement horizontal.
useRef
permet d'accéder directement à un élément du DOM sans avoir à re-render le composant. Évite des re-renders inutiles, caruseRef
ne déclenche pas de mise à jour du composant.
<motion.div ref={scrollRef} className="horizontal-scroll-content">
associescrollRef
au conteneur<motion.div>
.
scrollRef.current
contiendra une référence directe à cet élément DOM
- Sans
useRef
, il faudrait utiliserdocument.querySelector
, ce qui n'est pas optimal en React
fadedIndexes
→ Un tableau d’index des images qui doivent être transparentes.
// déclaration des hook
const scrollRef = useRef(null);
const [fadedIndexes, setFadedIndexes] = useState([]);
useEffect
pour détecter la visibilité des images
✅ handleScroll
:
- Récupère les dimensions des images par rapport au conteneur visible.
- Calcule le pourcentage visible de chaque image (
visibilityRatio
).
- Ajoute à
newFadedIndexes
toutes les images qui sont visibles à moins de 90%.
✅ useEffect
:
- Déclenche
handleScroll
au montage du composant.
- Ajoute un écouteur
scroll
sur le conteneur.
- Nettoie l'écouteur lors du démontage.
const container = scrollRef.current; // accès au DOM direct ici scrollRef contient la référence de motion.div
const children = Array.from(container.children);
container.children
retourne uneHTMLCollection
, soit les div
<motion.div class="horizontal-scroll-content">
<div class="card">1</div>
<div class="card">2</div>
<div class="card">3</div>
</motion.div>
getBoundingClientRect()
Cette méthode Javascript retourne la position et la taille d'un élément par rapport à la fenêtre (viewport).
📌 getBoundingClientRect()
renvoie un objet contenant ces propriétés :
rect.top
→ Distance entre le haut de l'élément et le haut de la fenêtre.
rect.left
→ Distance entre la gauche de l'élément et la gauche de la fenêtre.
rect.right
→ Distance entre la droite de l'élément et la gauche de la fenêtre.
rect.bottom
→ Distance entre le bas de l'élément et le haut de la fenêtre.
rect.width
→ Largeur de l'élément.
rect.height
→ Hauteur de l'élément.
const rect = child.getBoundingClientRect();
💡 IntersectionObserver
peut-etre utilisé à la place de getBoundingClientRect
rect.right : distance entre la droite de l’image et le bord de la fenêtre
rect.left : distance entre la gauche de l’image et le bord de la fenêtre
Ce code permet d'écouter l'événement scroll sur un élément spécifique et de le nettoyer correctement lors du démontage du composant.
À chaque défilement horizontal, la fonction handleScroll()
est appelée.
Le return
est une fonction de nettoyage qui s'exécute quand le composant est démonté.
Si on ne retire pas l’écouteur, il restera actif même si le composant n'existe plus, ce qui peut causer :
- Des bugs (exécuter du code sur un élément non monté).
- Des fuites mémoire (le composant garde en mémoire une référence inutile).
scrollRef.current.addEventListener("scroll", handleScroll);
return () =>
scrollRef.current.removeEventListener("scroll", handleScroll);
useEffect(() => {
const handleScroll = () => {
const container = scrollRef.current; // accès au DOM direct ici scrollRef contient la référence de motion.div
const children = Array.from(container.children);
let newFadedIndexes = [];
children.forEach((child, index) => {
const rect = child.getBoundingClientRect();
const containerRect = container.getBoundingClientRect();
const visibleWidth =
Math.min(rect.right, containerRect.right) -
Math.max(rect.left, containerRect.left);
const cardWidth = rect.width;
const visibilityRatio = visibleWidth / cardWidth;
// Appliquer la transparence uniquement si moins de 90% de la carte est visible
if (visibilityRatio < 0.9) {
newFadedIndexes.push(index);
}
});
setFadedIndexes(newFadedIndexes);
};
handleScroll();
scrollRef.current.addEventListener("scroll", handleScroll);
return () => scrollRef.current.removeEventListener("scroll", handleScroll);
}, []);
Rendu du composant
motion.div
→ Gère l’animation du défilement horizontal.
Parcourt images
et affiche chaque image dans une carte (<div className="card">
).
Ajoute la classe .faded
aux images qui sont dans fadedIndexes
, ce qui applique une transparence CSS.
useState
+ useEffect
Exercice apparition de blocs
Animer l'apparition d'un div
Ajout d’un identifiant unique à chaque carré et un état d'animation.
Utilisation de l'index comme identifiant au lieu d'un Date.now()
, mais avec précaution parce que l'index change si des éléments sont supprimés ou réorganisés, ce qui peut casser l'animation. Mais on ne modifie pas l'ordre des carrés, l'index reste une solution acceptable.
Hook react_app_test/src/hooks/useBoxes.js
- on récupère l’état de boxes :
setBoxes((prevBoxes) => {
carboxes
pourrait ne pas être à jour au moment de l'exécution. React ne met pas immédiatement à jour l’état (setState
est asynchrone).
- calcule l’index de la box dans le hook pour modifier dans le composant la class de la box qui a cet index
const useBoxes = (color) => {
const [animateBoxes, setAnimateBoxes] = useState([]); // Gère l'animation des carrés
const addBox = () => {
setBoxes((prevBoxes) => {
const newBoxes = [...prevBoxes, color];
const newIndex = newBoxes.length - 1; // On prend l'index du dernier élément ajouté
setAnimateBoxes([...animateBoxes, newIndex]);
setTimeout(() => {
setAnimateBoxes((prev) => prev.filter(index => index !== newIndex));
}, 500); // Retire l'effet après l'animation (500ms)
return newBoxes;
});
setShowMessage(true);
};
Composant react_app_test/src/components/CarreList.js
<div className={`carreList`}>
{boxes.map((boxColor, index) => (
<div className="carre" key={index}>
<div className={`carre ${animateBoxes.includes(index) ? 'fade-in' : ''}`} style={{backgroundColor: boxColor,}} onClick={() => document.getElementById(`color-picker-${index}`).click()}></div>
<input id={`color-picker-${index}`} type="color" value={boxColor} onChange={(event) => changeBoxColor(index, event.target.value)} style={{display: 'none'}}/>
</div>
))}
</div>
Exercice menu hamburger
Icone lucide
// pour installer
npm install lucide-react
// import de l'icone dans le composant
import { Menu, X } from "lucide-react";
react_app_test/src/components/HamburgerMenu.js
const [isOpen, setIsOpen] = useState(false);
// Fonction pour fermer le menu
const closeMenu = () => setIsOpen(false);
- bouton pour ouvrir ou fermer le menu
- sur le clic on inverse le statut (à la manière d’un toggle)
<X size={24} />
ajout de l’icone Lucide
<button className="menu-button" onClick={() => setIsOpen(!isOpen)}>
{isOpen ? <X size={24} /> : <Menu size={24} />}
</button>
- si statut “isOpen” est à true on écrit le div dans le DOM. Et si statut est false, le div ne sera pas présent dans le DOM
{isOpen && (
<div className="menu-dropdown">
<ul>
<li><Link to="/" onClick={closeMenu}>Accueil</Link></li>
<li><Link to="/mentions-legales" onClick={closeMenu}>Mentions légales</Link></li>
<li><Link to="/exercice-1" onClick={closeMenu}>Exercice 1</Link></li>
<li><Link to="/exercice-2" onClick={closeMenu}>Exercice 2</Link></li>
<li><Link to="/exercice-3" onClick={closeMenu}>Exercice 3</Link></li>
<li><Link to="/exercice-4" onClick={closeMenu}>Exercice 4</Link></li>
<li><Link to="/exercice-5" onClick={closeMenu}>Exercice 5</Link></li>
<li><Link to="/exercice-6" onClick={closeMenu}>Exercice 6</Link></li>
</ul>
</div>
)}
- Dans le menu on met une action qui ferme le menu si l’internaute clique sur un lien
<li><Link to="/" onClick={closeMenu}>Accueil</Link></li>
- backdrop
- Quand le menu est ouvert, c’est “couvrir” le reste de la page avec une couche au-dessous du menu hamburger ouvert pour avoir ce div qui sert de couverture et agir dessus : ici si on clique dessus cela ferme le menu hamburger
{isOpen && <div className="menu-backdrop" onClick={closeMenu}></div>}
PROJET D’INVENTAIRE DE COULEURS DE SITES INSPIRANTS
Page accueil - On dit bonjour au visiteur + jeu de couleurs
1 - Maquette
On commence par faire la maquette de la page et on fait l’inventaire des composants en leur donnant un nom.
- au niveau de la page
- Header
- Navigation
- Main Content
- Footer
- au niveau des composants dans chaque sections de la page
- section
- chaque élément de la section
- section
2 - on créé les pages
Dans votre dossier src, créez un dossier pages pour contenir toutes les pages de votre application
- src/
- pages/
- Home.js (page accueil)
- Legal.js (page mentions légales)
- components/
- Header.js
- Footer.js
- App.js
- pages/
Page d’accueil (Home.js)
import React from 'react';
function Home() {
return (
ICI ON MET LES COMPOSANTS DE LA PAGE
);
}
export default Home;
3 - on place les composants les uns après les autres
on créé des fichiers pour les différentes parties de la page
- src/
- components/
- Header.js
- Navigation.js
- Footer.js
- MainContent.js
- App.js
- components/
- src/
Ensuite on créé les composants dans chaque section
- avec
- HTML (via JSX) : La structure visuelle.
- CSS : Styles spécifiques au composant.
- on code le css en scss avec l’architecture sass
- Logique React : Gestion de l’état, événements, etc.
- Utilisez useState pour gérer l’état local.
- Passez des props entre les composants pour transmettre des données.
- avec
PAGE ACCUEIL et ses fonctions dynamiques
Affichage dynamique du prénom avec la couleur choisie
React.useState()
-
useState est un hook de React qui permet à un composant de
- 1. Définir une valeur d’état initiale.
- 2. Mettre à jour cette valeur lorsque nécessaire.
- 3. Re-rendre le composant automatiquement lorsqu’on change la valeur de l’état.
syntaxe générale :const [state, setState] = React.useState(initialValue);
Un hook en React est une fonction spéciale qui permet d’utiliser certaines fonctionnalités de React
// on déclare la variable d'état pour stocker le nom de la personne saisie par l'utilisateur. // ici personName : Une variable d’état qui stocke le nom de la personne. // ici setPersonName : Une fonction pour mettre à jour la valeur de personName. // ici '' : La valeur initiale de personName est une chaîne vide. const [personName,setPersonName] = React.useState(''); // Fonction déclenchée lorsqu'une saisie est faite dans le champ texte. // Met à jour l'état `personName` avec la valeur saisie. // event contient les informations de l’événement déclenché avec onClick // target Représente l’élément HTML sur lequel l’événement a eu lieu. Dans ce cas, c’est le champ de saisie <input>. const handleInputChange = (event) => { setPersonName(event.target.value); }; {/* Champ texte pour saisir le prénom */} <div className="formBonjour_prenom"> <input type="text" onChange={handleInputChange} placeholder="Entrer votre prénom"/> {/* Appelle `handleInputChange` lorsque l'utilisateur tape */} </div> {/* Affichage dynamique du prénom avec la couleur choisie */} <div className="bonjour"> <div> <h1>Bonjour <span style={{ color: color }}>{personName}</span></h1> </div> </div>
Choix de la couleur par le visiteur
// État pour stocker la couleur choisie par l'utilisateur. // Valeur initiale : noir (#000000). const [color, setColor] = React.useState('#000000'); // Couleur initiale // Fonction déclenchée lorsqu'une couleur est sélectionnée. // Met à jour l'état `color` avec la couleur choisie. // Fonction pour choisir la couleur const handleColorChange = (event) => { setColor(event.target.value); }; {/* Section pour choisir une couleur */} {/* type="color" pour proposer un choix de la couleur avec une palette système */} <div className="formBonjour_couleur"> <h1>Choisissez une couleur</h1> <input type="color" value={color} onChange={handleColorChange}/> <i>{color}</i> {/* Affiche la valeur hexadécimale de la couleur */} </div> {/* Affichage dynamique du prénom avec la couleur choisie */} <div className="bonjour"> <div> <h1>Bonjour <span style={{ color: color }}>{personName}</span></h1> </div> </div>
Créer des carrés de couleurs / Afficher le nombre de carrés ajoutés
Règle sur les états : en React, l’état est immuable :
• Cela signifie que vous ne pouvez pas modifier directement l’état existant, comme
boxes.push({})
, car cela ne crée pas de nouvelle référence.C’est pour cela que l’on utilise l’opérateur
spread (...)
pour copier tous les éléments existants du tableau boxes et créer un nouveau tableau.La méthode .map()
est utilisée pour parcourir chaque élément du tableau et retourner une nouvelle liste d’éléments React basés sur le contenu du tableau.boxes.map((_, index) : _ représente l’élément en cours de lecture (sur l’itération de lecture du tableau avec map()). On met _ car c’est utilisé ici comme une variable ignorée car on n’a pas besoin de son contenu. On aurait pu mettre “box”
index : représente l’index de l’élément actuel dans le tableau boxes.
• Utilisé ici pour attribuer une clé unique à chaque <div> généré.key est une propriété spéciale en React utilisée pour identifier de manière unique chaque élément de la liste générée.
// État pour stocker les carrés ajoutés (sous forme de tableau vide). const [boxes, setBoxes] = React.useState([]); // État pour stocker les divs // Fonction pour ajouter un nouveau carré. // Ajoute un nouvel élément vide (`{}`) au tableau `boxes`. // L’opérateur spread (...) copie tous les éléments existants du tableau boxes. // [...boxes, {}] Crée un nouveau tableau contenant : // • Tous les éléments actuels de boxes (grâce à ...boxes). // • Un nouvel objet vide ({}) à la fin du tableau. const addBox = () => { setBoxes([...boxes, {}]); }; {/* Bouton pour ajouter des carrés */} <div> <h1>Ajoutez des carrés</h1> <button onClick={addBox}>Ajouter un carré</button> {/* Appelle `addBox` au clic */} </div> {/* Conteneur qui affiche les carrés ajoutés */} <div className="carreList"> {/* Parcours du tableau `boxes` pour afficher un carré pour chaque élément */} {boxes.map((_, index) => ( <div className="carre" key={index} style={{backgroundColor: color,}}></div> // Utilise `index` comme clé unique pour chaque carré ))} </div> {/* Affiche le nombre de carrés ajoutés */} <div> <p>Nombre de carrés ajoutés : {boxes.length}</p> </div>
Possibilité de modifier la couleur d’un carré
Ajouter un compteur de secondes
Dans le footer
- Fonction
setInterval(callback, timeout)
déclenche un traitement à intervalles réguliers. timeout en millisecondes.
La fonction clearInterval() est utile pour arrêter le traitement récurrent.
- Toutes les secondes la variable “count” est mise à jour. Lors de cette mise à jour le composant Counter() est de nouveau exécuter pour s’actualiser.
Cela provoque donc la mise en route d’un nouveau timer avec
setInterval(). De ce fait plusieurs compteur setInterval() sont lancés ce qui provoque un affichage du temps écoulé anarchique.
Pour
corriger cela nous allons utiliser un autre hook de React :useEffect(callback)
qui permet d’effectuer une traitement avant chaque affichage (c’est à dire avant que le composant soit mis à jour).
Il faut, en effet, que l’on supprime le timer avant le mise à jour du compteur dans la page HTML, pour éviter les chevauchements des lancements des timer à chaque rechargement du composant. Le traitement indiqué dans la fonction de callback retournée (soit le “return”) par useEffect sera exécuté avant chaque mise à jour du composant. Nous allons donc supprimer le timer avant chaque affichage du compteur.React.useEffect(function() { var timer = setInterval(function() { setCount(count+1); console.log("count = ", count); }, 1000) return function() { clearInterval(timer); } });
- Fonction
ROUTEUR ET NAVIGATION
Quand l’utilisateur clique sur un lien (<Link to="/"> ou <Link to="/mentions-legales">), React Router intercepte cet événement.
• Au lieu de recharger la page (comme dans une application classique côté serveur), React Router met à jour l’URL dans le navigateur et rend dynamiquement le composant associé à cette route.
• path="/" rend le composant <Home />.
• path="/mentions-legales" rend le composant <Legal />.
Création des routes et navigations
- Il faut installer React Router
- React Router utilise un routage côté client (Single Page Application - SPA).
- React Router associe chaque URL à un composant React défini dans vos routes.
- Les routes (par exemple, / ou /mentions-legales) ne correspondent pas directement à des fichiers comme dans un serveur traditionnel.
npm install react-router-dom
- React Router utilise un routage côté client (Single Page Application - SPA).
- Configurez les routes dans un fichier pour les routes (AppRoutes.js)
Les fichiers Home.js et Legal.js sont importés dans le fichier où les routes sont définies. Ces fichiers ne sont pas “retrouvés” directement à partir des liens, mais sont rendus dynamiquement lorsque l’URL correspond à une route.
///////////////////////////
// VERSION 1 (de base)
///////////////////////////
import React from 'react';
import { Routes, Route } from 'react-router-dom';
import Home from '../pages/Home';
import Legal from '../pages/Legal';
function AppRoutes() {
return (
<Routes>
<Route path="/" element={<Home />} /> {/* Page d'accueil */}
<Route path="/mentions-legales" element={<Legal />} />
</Routes>
);
}
export default AppRoutes;
///////////////////////////
// VERSION 2 (optimisé)
///////////////////////////
import React from 'react';
import { Routes, Route } from 'react-router-dom';
import Home from '../pages/Home';
import Legal from '../pages/Legal';
function AppRoutes() {
// tableau contenant les objets routes
const routesConfig = [
{ path: "/", element: <Home /> },
{ path: "/mentions-legales", element: <Legal /> },
];
const routes = (
<Routes>
{routesConfig.map((route, index) => (
<Route key={index} path={route.path} element={route.element} />
))}
</Routes>
);
return routes;
}
export default AppRoutes;
- Ajoutez des liens pour naviguer entre les pages
- Dans le composant Header, ajoutez des liens vers vos différentes pages.
import React from 'react'; import { Link } from 'react-router-dom'; function Header() { return ( <header> <nav> <ul> <li><Link to="/">Accueil</Link></li> <li><Link to="/mentions-legales">Mentions légales</Link></li> </ul> </nav> </header> ); } export default Header;
Protected routes
Les routes protégées (ou protected routes) sont des routes dans une application web qui ne sont accessibles qu’à des utilisateurs authentifiés ou ayant les permissions requises. Si un utilisateur tente d’accéder à une route protégée sans les autorisations nécessaires, il est généralement redirigé vers une autre page, comme une page de connexion.
CHARGEMENT DES PAGES
React est une Single Page Application (SPA)
Dans une application React classique tout le site est chargé d’un coup dans le navigateur:
- Lorsque vous déployez une application React, des outils comme Webpack ou Vite regroupent tout le code (JavaScript, CSS, images) en fichiers optimisés.
- Ces fichiers sont généralement chargés au départ, ce qui peut inclure tous les composants de l’application, même ceux qui ne sont pas immédiatement visibles.
- Le navigateur charge une seule page HTML (souvent index.html) au départ.
- Ensuite, toute la logique et l’interface utilisateur sont gérées par React côté client.
- React Router ne recharge pas la page entière lorsque vous naviguez, mais met à jour l’URL et rend dynamiquement les composants associés à la nouvelle route.
Premier chargement plus long :
- Si tout le site est chargé dans un gros bundle, le temps de chargement initial peut être plus long.
- Cela peut être résolu avec le lazy loading et la division du code (code splitting)
SEO moins efficace par défaut :
- Dans une SPA, tout le contenu est généré côté client, ce qui peut poser problème pour les moteurs de recherche.
- Solution : Utiliser un rendu côté serveur (SSR) avec un framework comme Next.js.
lazy loading
- Si vous configurez le “code splitting” ou le “lazy loading”, React ne charge que les composants nécessaires pour la route actuelle.
- Les autres composants seront chargés à la demande, uniquement lorsque l’utilisateur navigue vers une route qui les nécessite.
- Pour optimiser le chargement, vous pouvez charger les composants uniquement lorsque leur route est visitée.
- React.lazy charge les composants Home et About seulement quand ils sont nécessaires.
- Si l’utilisateur ne visite jamais /about, le fichier JavaScript correspondant ne sera jamais chargé.
- La balise <Suspense> affiche un indicateur de chargement (Chargement...) pendant le téléchargement des composants.
import React, { Suspense } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
// Lazy loading des composants
const Home = React.lazy(() => import('./pages/Home'));
const Legal = React.lazy(() => import('./pages/Legal'));
function AppRoutes() {
return (
<Router>
<Suspense fallback={<div>Chargement...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/mentions-legales" element={<Legal />} />
</Routes>
</Suspense>
</Router>
);
}
export default AppRoutes;
Next.js
EXERCICES
- Améliorer le compteur de temps en mettant
- si < 60 sec = Vous regarder cette page depuis : 25 secondes.
- si < 60 min = Vous regarder cette page depuis : 35 minutes et 25 secondes.
- si < 24h = Vous regarder cette page depuis : 8 heures 35 minutes et 25 secondes.
- si > 24h = Vous regarder cette page depuis : 2 jours 8 heures 35 minutes et 25 secondes.
- Améliorer le rendu de la page ⇒ faire un design web
BUILD
Lors du build (par exemple, avec npm run build), Webpack regroupe tous les fichiers en un seul bundle JavaScript optimisé.
• Ce bundle est chargé dans le navigateur lors de l’accès initial à l’application. Tous les composants (comme Home ou Legal) sont disponibles en mémoire.
TYPESCRIPT
Option 1 : Créer un projet React avec TypeScript
Vous pouvez créer un projet React avec TypeScript en utilisant Create React App :
npx create-react-app my-app --template typescript
Option 2 : Ajouter TypeScript à un projet existant
Si vous avez déjà un projet React basé sur JavaScript, vous pouvez ajouter TypeScript :
- Installez les dépendances nécessaires :
npm install typescript @types/react @types/react-dom
- Renommez les fichiers .js en .tsx.
- Créez ou mettez à jour le fichier tsconfig.json pour configurer TypeScript.