Aller au contenu

React : composants et JSX

Un composant est une fonction qui renvoie du JSX (du HTML dans du JavaScript). Son nom commence par une majuscule.

function Salutation() {
const nom = 'Alice';
const actif = true;
return (
<section className="carte">
<h2>Bonjour {nom}</h2>
<p style={{ color: actif ? 'green' : 'gray' }}>
{actif ? 'Connectée' : 'Hors ligne'}
</p>
<label htmlFor="champ">Nom</label>
<input id="champ" type="text" />
</section>
);
}

Différences avec le HTML : className (et non class), htmlFor (et non for), attributs en camelCase (onClick, tabIndex), balises toujours fermées (<input />), un seul élément racine par composant.

Une expression entre accolades {…} peut contenir n’importe quelle expression JavaScript, pas d’instruction (if, for).

type Props = {
titre: string;
prix: number;
enStock?: boolean;
};
function Produit({ titre, prix, enStock = true }: Props) {
return (
<article>
<h3>{titre}</h3>
<p>{prix.toFixed(2)} €</p>
{!enStock && <p>Rupture de stock</p>}
</article>
);
}
<Produit titre="Clavier" prix={49} />;

Les props sont en lecture seule : un composant ne les modifie jamais.

import type { ReactNode } from 'react';
function Carte({ titre, children }: { titre: string; children: ReactNode }) {
return (
<section className="carte">
<h2>{titre}</h2>
{children}
</section>
);
}
<Carte titre="Profil">
<p>Contenu passé entre les balises.</p>
</Carte>;

La composition (passer des éléments en children ou en props) est préférée à l’héritage.

type Client = { id: number; nom: string };
function Liste({ clients }: { clients: Client[] }) {
return (
<ul>
{clients.map((c) => (
<li key={c.id}>{c.nom}</li>
))}
</ul>
);
}

La prop key identifie chaque élément : elle doit être stable et unique parmi les frères (un identifiant de la donnée). Éviter l’index du tableau si la liste peut être réordonnée, filtrée ou modifiée.

function Statut({
erreur,
chargement,
donnees,
}: {
erreur?: string;
chargement: boolean;
donnees?: string[];
}) {
if (chargement) return <p>Chargement…</p>;
if (erreur) return <p role="alert">Erreur : {erreur}</p>;
if (!donnees?.length) return <p>Aucun résultat.</p>;
return (
<ul>
{donnees.map((d) => (
<li key={d}>{d}</li>
))}
</ul>
);
}

Attention à {nombre && <p>…</p>} : si nombre vaut 0, React affiche « 0 ». Écrire {nombre > 0 && …}.

function Lignes() {
return (
<>
<tr>
<td>A</td>
</tr>
<tr>
<td>B</td>
</tr>
</>
);
}

<>…</> regroupe des éléments sans ajouter de balise au DOM.

src/
├── components/ # composants réutilisables (Bouton, Carte, Modal)
├── pages/ ou routes/ # composants d'écran
├── hooks/ # hooks personnalisés (useXxx)
├── lib/ # fonctions utilitaires, clients d'API
└── types/
  • Un composant par fichier, nommé comme le composant.
  • Exporter par défaut pour les pages, nommé pour les composants partagés (au choix, mais cohérent).
  • Séparer présentation (affichage) et logique (hooks, appels d’API) quand un composant grossit.
import './Carte.css'; // CSS classique
<div className="carte carte--active" />;
<div style={{ width: `${pourcent}%` }} />; // style dynamique

Avec Tailwind : classes utilitaires dans className (voir Tailwind : utilitaires et Organisation et composants).

  • Utiliser les balises sémantiques (button, nav, main, label) plutôt que des div cliquables.
  • Toujours un alt sur <img> (vide si décorative).
  • Associer chaque champ à un <label>.
  • Gérer le focus et le clavier pour les composants personnalisés (menu, boîte de dialogue).
Symptôme Piste
Warning: Each child in a list should have a unique "key" prop Ajouter key à l’élément de map
Adjacent JSX elements must be wrapped Entourer par un fragment <>…</>
Le composant s’affiche comme du texte (<monComposant>) Nom en minuscule : première lettre en majuscule
Objects are not valid as a React child Afficher un objet : afficher ses champs ou JSON.stringify
0 affiché {n && …} avec n valant 0
Cannot read properties of undefined Donnée pas encore chargée : prévoir l’état de chargement

Ubuntu 24.04 et 26.04 : différences à connaître

Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »

Aucune.