Chapitre 2 : JSX
Qu'est-ce que JSX ?
JSX (JavaScript XML) est une extension de syntaxe qui permet d'écrire du HTML dans JavaScript :
const element = <h1>Bonjour le monde !</h1>;
Ce n'est pas du HTML. C'est du JavaScript qui sera transformé en appels de fonctions React.
// Ce JSX :
const element = <h1 className="title">Bonjour</h1>;
// Est transformé en :
const element = React.createElement('h1', { className: 'title' }, 'Bonjour');
Vous n'avez pas besoin d'écrire React.createElement - le compilateur (Babel/Vite) le fait pour vous.
Différences avec HTML
className au lieu de class
class est un mot réservé en JavaScript :
// HTML
<div class="container">
// JSX
<div className="container">
htmlFor au lieu de for
// HTML
<label for="email">
// JSX
<label htmlFor="email">
Style en objet
// HTML
<div style="color: red; font-size: 16px;">
// JSX - objet avec camelCase
<div style={{ color: 'red', fontSize: '16px' }}>
// Ou avec une variable
const styles = { color: 'red', fontSize: '16px' };
<div style={styles}>
Attributs en camelCase
// HTML
<button onclick="handleClick()">
<input tabindex="1">
// JSX
<button onClick={handleClick}>
<input tabIndex={1}>
Fermeture obligatoire des balises
// HTML
<img src="/img/training/module2-introduction-react/photo.jpg">
<input type="text">
<br>
// JSX - toujours fermer
<img src="/img/training/module2-introduction-react/photo.jpg" />
<input type="text" />
<br />
Expressions JavaScript dans JSX
Utilisez les accolades {} pour insérer du JavaScript :
Variables
const name = "Jean";
const age = 30;
return (
<div>
<p>Nom : {name}</p>
<p>Age : {age}</p>
<p>Année de naissance : {2024 - age}</p>
</div>
);
Fonctions
function formatName(user) {
return `${user.firstName} ${user.lastName}`;
}
const user = { firstName: 'Jean', lastName: 'Dupont' };
return <h1>Bonjour, {formatName(user)} !</h1>;
Expressions, pas de statements
Dans les accolades, vous pouvez mettre des expressions (qui retournent une valeur), pas des statements (if, for, while).
// CORRECT - expressions
{name}
{2 + 2}
{formatName(user)}
{isAdmin ? 'Admin' : 'User'}
{items.length}
// INCORRECT - statements
{if (isAdmin) { return 'Admin' }} // Erreur !
{for (let i = 0; i < 10; i++) {}} // Erreur !
Conditions
Opérateur ternaire
Pour afficher une chose ou une autre :
function Greeting({ isLoggedIn }) {
return (
<div>
{isLoggedIn ? (
<p>Bienvenue !</p>
) : (
<p>Veuillez vous connecter</p>
)}
</div>
);
}
Opérateur &&
Pour afficher quelque chose ou rien :
function Notification({ count }) {
return (
<div>
{count > 0 && (
<span className="badge">{count}</span>
)}
</div>
);
}
Attention : {count && <span>...</span>} affichera 0 si count vaut 0, car 0 est une valeur "falsy" mais affichable. Préférez {count > 0 && ...}.
Variables pour les cas complexes
function UserStatus({ user }) {
let statusMessage;
if (user.isAdmin) {
statusMessage = <span className="admin">Administrateur</span>;
} else if (user.isPremium) {
statusMessage = <span className="premium">Premium</span>;
} else {
statusMessage = <span>Standard</span>;
}
return <div>{statusMessage}</div>;
}
Boucles avec map()
Pour afficher une liste, utilisez map() :
function UserList({ users }) {
return (
<ul>
{users.map(user => (
<li key={user.id}>
{user.name}
</li>
))}
</ul>
);
}
L'attribut key
Obligatoire pour les listes. Permet à React d'identifier chaque élément :
// CORRECT - ID unique
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
// ACCEPTABLE - si pas d'ID, utiliser l'index (moins performant)
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
// INCORRECT - pas de key
{users.map(user => (
<li>{user.name}</li> // Warning React !
))}
Comparaison avec PHP
// PHP
<?php foreach ($users as $user): ?>
<li><?= $user['name'] ?></li>
<?php endforeach; ?>
// React
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
Fragments
Un composant doit retourner un seul élément racine. Si vous ne voulez pas ajouter de <div> inutile, utilisez un Fragment :
// INCORRECT - plusieurs éléments racine
function UserInfo({ user }) {
return (
<h1>{user.name}</h1>
<p>{user.email}</p> // Erreur !
);
}
// CORRECT - avec Fragment
function UserInfo({ user }) {
return (
<>
<h1>{user.name}</h1>
<p>{user.email}</p>
</>
);
}
// Ou la syntaxe longue
import { Fragment } from 'react';
function UserInfo({ user }) {
return (
<Fragment>
<h1>{user.name}</h1>
<p>{user.email}</p>
</Fragment>
);
}
Exercices
Exercice 1 : Convertir en JSX
Convertir ce HTML en JSX :
<div class="card">
<img src="/img/training/module2-introduction-react/photo.jpg" alt="Photo">
<label for="name">Nom :</label>
<input type="text" id="name" tabindex="1">
<button onclick="save()">Sauvegarder</button>
</div>
Solution :
<div className="card">
<img src="/img/training/module2-introduction-react/photo.jpg" alt="Photo" />
<label htmlFor="name">Nom :</label>
<input type="text" id="name" tabIndex={1} />
<button onClick={save}>Sauvegarder</button>
</div>
Exercice 2 : Affichage conditionnel
Créer un composant qui affiche :
- "Chargement..." si
loadingest true - "Aucun résultat" si
itemsest vide - La liste des items sinon
Solution :
function ItemList({ loading, items }) {
if (loading) {
return <p>Chargement...</p>;
}
if (items.length === 0) {
return <p>Aucun résultat</p>;
}
return (
<ul>
{items.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
Points clés à retenir
- JSX n'est pas HTML : c'est du JavaScript transformé
- className au lieu de class, htmlFor au lieu de for
- Accolades
{}pour insérer du JavaScript - Ternaire
? :ou && pour les conditions - map() pour les boucles, avec une key unique
- Fragments
<></>pour retourner plusieurs éléments
← Chapitre précédent | Retour au module | Chapitre suivant : Composants ->