Cet article présente les bases essentielles de React, en couvrant les concepts clés, l'installation et les hooks intégrés.
1. Créer et imbriquer des composants
Une application React est cosntruite à partir de composants. Un composant représente une partie de l'interface utilisateur (UI) avec sa propre logique et son apparence. Il peut être aussi petit qu'un bouton ou aussi grand qu'une page entière.
Les composants React doivent commencer par une majuscule, tandis que les balises HTML doivent être en minuscules.
function MonBouton() {
return (
<button>Je suis un bouton</button>
);
}
export default function MonApp() {
return (
<div>
<h1>Bienvenue dans mon application</h1>
<MonBouton />
</div>
);
}
2. Utiliser JSX
JSX est plus strict que HTML. Vous devez fermer les balises, comme
<br />. Un composant ne peut pas retourner plusieurs balises JSX ; elles doivent être enveloppées dans un parent commun, comme<div>...</div>ou<>...</>.
function PageAPropos() {
return (
<>
<h1>À propos</h1>
<p>Bonjour tout le monde.<br />Comment allez-vous ?</p>
</>
);
}
3. Ajouter des styles
En React, utilisez className pour spécifier une classe CSS, similaire à l'attribut class en HTML.
<img className="utilisateur" />
.utilisateur {
background: red;
}
Styles en ligne :
<div style={{width: "300px", backgroundColor: "red"}}></div>
4. Afficher des données
Utilisez { } dans JSX pour exécuter du code JavaScript.
const [visible, setVisible] = useState(false);
const titre = "Titre";
return (
<>
{visible ? <h1>{titre}</h1> : null}
</>
);
Pour assigner une variable JavaScript à un attribut HTML, utilisez { } et non des guillemets.
<img src="utilisateur" /> // Passe la chaîne "utilisateur" à src
<img src={userPng} /> // Passe la variable userPng à src
5. Rendu conditionnel
React n'a pas de syntaxe spéciale pour les conditions ; utilisez du JavaScript standard.
let contenu;
if (estConnecte) {
contenu = <PanneauAdmin />;
} else {
contenu = <FormulaireConnexion />;
}
return (
<div>
{contenu}
</div>
);
// Opérateur ternaire ?
<div>
{estConnecte ? (
<PanneauAdmin />
) : (
<FormulaireConnexion />
)}
</div>
// Opérateur logique &&
<div>
{estConnecte && <PanneauAdmin />}
</div>
6. Rendu de listes
N'oubliez pas de définir l'attribut
key, similaire à:keydans Vue.js.
const produits = [{id: 1, titre: "nom1"}, {id: 2, titre: "nom2"}];
return (
<ul>
{produits.map(produit =>
<li key={produit.id}>
{produit.titre}
</li>
)}
</ul>
);
7. Réagir aux événements
Notez que
onClick={handleClick}n'a pas de parenthèses. Ne déclenchez pas la fonction de gestion d'événement ; passez la fonction à l'événement. React l'appellera lors du clic.
function MonBouton() {
function handleClick() {
alert('Vous m\'avez cliqué !');
}
return (
<button onClick={handleClick}>
Cliquez-moi
</button>
);
}
8. Mettre à jour l'interface
useState (similaire à ref() ou reactive() dans Vue.js) crée des données réactives qui mettent à jour l'interface lorsqu'elles changent.
Lorsque React re-rend un composant :
- React appelle à nouveau votre fonction
- La fonction retourne un nouvel instentané JSX
- React met à jour l'interface pour correspondre à cet instantané
import { useState } from 'react';
export default function MonApp() {
return (
<div>
<h1>Compteurs qui se mettent à jour séparément</h1>
<MonBouton />
<MonBouton />
</div>
);
}
function MonBouton() {
const [compteur, setCompteur] = useState(0);
function handleClick() {
setCompteur(compteur + 1);
}
return (
<button onClick={handleClick}>
Cliqué {compteur} fois
</button>
);
}
9. Utiliser les hooks
Les fonctions commençant par use sont appelées hooks. useState est un hook intégré à React. Vous pouvez créer vos propres hooks en combinant des hooks existants.
Les hooks sont plus stricts que les fonctions normales. Vous ne devez les appeler qu'au niveau supérieur de votre composant (ou d'autres hooks). Si vous voulez utiliser
useStatedans une condition ou une boucle, extrayez un nouveau composant et utilisez-le à l'intérieur.
10. Partager des données entre composants
Remontez la variable à un parent commun et passez-la via les props.
export default function MonApp() {
const [compteur, setCompteur] = useState(0);
function handleClick() {
setCompteur(compteur + 1);
}
return (
<div>
<h1>Compteurs qui se mettent à jour ensemble</h1>
<MonBouton compteur={compteur} onClick={handleClick} />
<MonBouton compteur={compteur} onClick={handleClick} />
</div>
);
}
function MonBouton({ compteur, onClick }) {
return (
<button onClick={onClick}>
Cliqué {compteur} fois
</button>
);
}
11. Principes de conception des états (state)
Suivez ces principes pour une meilleure gestion des états :
- Fusionner les états liés : si vous mettez toujours à jour deux états en même temps, fusionnez-les en un seul.
- Éviter les états contradictoires : évitez les structures où des états peuvent s'opposer.
- Éviter les états redondants : ne stockez pas des informations calculables à partir des props ou d'autres états.
- Éviter les états dupliqués : la duplication rend la synchronisation difficile.
- Éviter les états imbriqués : privilégiez une structure plate pour faciliter les mises à jour.
Installation
1. Démarrer un nouveau projet React
- Outil de base :
npx create-react-app - Frameworks full-stack :
- Next.js :
npx create-next-app@latest - Remix :
npx create-remix
- Next.js :
2. Utiliser TypeScript
TypeScript supporte JSX nativement. Ajoutez
@types/reactet@types/react-dompour une compatibilité complète.
npm install @types/react @types/react-dom
Hooks intégrés
Hooks d'état
useState est le hook principal pour gérer l'état local.
Hooks de contexte
Le contexte permet à un composant de recevoir des informations d'un ancêtre sans les passer via les props.
function Bouton() {
const theme = useContext(ThemeContext);
// ...
}
Hooks de référence
useRef permet de stocker des informations qui ne sont pas utilisées pour le rendu, comme des nœuds DOM ou des ID de minuteur.
const iptRef = useRef(null);
const minuteur = useRef(null);
useEffect(() => {
iptRef.current.focus();
minuteur.current = setInterval(() => {
faireQuelqueChose();
}, 100);
return () => {
clearInterval(minuteur.current);
};
}, []);
return <input ref={inputRef} />;
Hooks d'effet
useEffect permet de gérer les effets de bord (appels réseau, DOM, etc.).
function ListeCartes() {
const [liste, setListe] = useState([]);
const [page, setPage] = useState(0);
useEffect(() => {
axios.get('/api/data').then((res) => {
setListe(res.data);
});
return () => {
// Nettoyage lors du démontage
};
}, []);
useEffect(() => {
// Exécuté lorsque page change
}, [page]);
return (
<ol>
{liste.map((item) => (
<li key={item.id}>{item.titre}</li>
))}
</ol>
);
}
useLayoutEffect s'exécute avant le rendu à l'écran (peu utilisé).
useInsertionEffect s'exécute avant les modifications DOM par React (peu utilisé).
Hooks de performance
useMemo: met en cache des calculs coûteux.useCallback: met en cache des définitions de fonctions.useTransition: marque des transitions comme non bloquantes.useDeferredValue: retarde la mise à jour de parties non critiques de l'interface.
Hooks de ressources
use(resource) permet de lire des ressources comme des Promises ou des contextes.
Contrairement aux autres hooks,
usepeut être appelé dans des boucles et des conditions. Il suspend le composant jusqu'à la résolution de la Promise.
import { createContext, use } from 'react';
const ThemeContext = createContext(null);
export default function MonApp() {
return (
<ThemeContext.Provider value="dark">
<Formulaire />
</ThemeContext.Provider>
);
}
function Formulaire() {
return (
<Panneau titre="Bienvenue">
<Bouton show={true}>S'inscrire</Bouton>
<Bouton show={false}>Se connecter</Bouton>
</Panneau>
);
}
function Panneau({ titre, enfants }) {
const theme = use(ThemeContext);
const className = 'panneau-' + theme;
return (
<section className={className}>
<h1>{titre}</h1>
{enfants}
</section>
);
}
function Bouton({ show, enfants }) {
if (show) {
const theme = use(ThemeContext);
const className = 'bouton-' + theme;
return (
<button className={className}>
{enfants}
</button>
);
}
return null;
}
import React, { ErrorBoundary, Suspense, use } from "react";
export function Utilisateur({ getUser }) {
return (
<ErrorBoundary fallback={<p>Erreur...</p>}>
<Suspense fallback={<p>Chargement...</p>}>
<Message getUser={getUser} />
</Suspense>
</ErrorBoundary>
);
}
const getUser = axios.get("/api/user");
function Message({ getUser }) {
const contenu = use(getUser);
return <p>Utilisateur : {contenu}</p>;
}
useReducer
Une alternative à useState pour des états complexes impliquant plusieurs sous-valeurs.
Composants intégrés courants
Fragment
<Fragment> (ou <>...</>) permet de regrouper des éléments sans ajouter un nœud parent supplémentaire.
Attention :
- Si vous devez passer une
keyà un fragment, utilisez<Fragment key={votreKey}>.- La transformation de
<><Enfant /></>en[<Enfant />]ne réinitialise pas l'état (sauf si imbriqué).
Suspense
<Suspense fallback={<Chargement />}>
{/* Affiche Chargement tant que QuelqueComposant n'est pas prêt */}
<QuelqueComposant />
</Suspense>
children : contenu UI réel ; fallback : UI de remplacement pendant le chargement.