Cours JavaScript et React · Module 1: Bases de React
La syntaxe JSX
Dans cette leçon5
JSX (JavaScript XML) est une extension de syntaxe pour JavaScript qui te permet d'écrire du code ressemblant à du HTML directement dans JavaScript. C'est une façon déclarative de décrire l'apparence que doit avoir la structure de l'UI dans React.
Qu'est-ce que JSX exactement ?
Pour un programmeur qui débute son aventure avec React, JSX peut sembler étrange : comment se fait-il qu'au beau milieu de JavaScript apparaissent soudain des balises de type HTML ?
Imagine JSX comme un traducteur entre le monde de JavaScript et le monde du HTML. Il te permet de décrire la structure de l'UI d'une façon lisible pour les humains (semblable au HTML) tout en conservant toute la puissance de JavaScript.
Comment fonctionne JSX en coulisses ?
Il est important de comprendre que les navigateurs ne comprennent pas nativement JSX. Avant que le code n'atteigne le navigateur, il est compilé en JavaScript ordinaire par des outils comme Babel.
Par exemple, ce code JSX :
1const element = <h1>Hello, world!</h1>;Est transformé en :
1const element = React.createElement(
2 'h1',
3 null,
4 'Hello, world!'
5);C'est pourquoi les anciennes versions de React (jusqu'à la 16) exigeaient d'importer React dans chaque fichier contenant du JSX. Depuis React 17, des outils comme Vite utilisent la nouvelle transformation JSX : le compilateur importe lui-même les fonctions nécessaires depuis react/jsx-runtime, donc import React from 'react' n'est plus nécessaire.
Les règles du JSX
JSX peut ressembler à du HTML, mais il possède plusieurs particularités et règles qu'il vaut la peine de comprendre :
1. Les noms d'attributs sont en camelCase
Contrairement au HTML, où les attributs s'écrivent en minuscules, en JSX de nombreux attributs s'écrivent au format camelCase :
1// HTML
2<div onclick="handleClick()" tabindex="0" class="container">
3
4// JSX
5<div onClick={handleClick} tabIndex={0} className="container">Remarque les différences :
onclick->onClicktabindex->tabIndexclass->className(parce que « class » est un mot réservé en JavaScript)
2. Les valeurs d'attributs sont des expressions JavaScript
En JSX, les valeurs d'attributs ne sont pas toujours des chaînes de caractères. Tu peux utiliser n'importe quelle expression JavaScript en l'entourant d'accolades :
1// Valeur numérique
2<input maxLength={10} />
3
4// Expression
5<img src={user.avatarUrl} />
6
7// Opérateur ternaire (opérateur conditionnel)
8<div className={isActive ? 'active' : 'inactive'}>
9
10// Fonction
11<button onClick={handleClick}>3. Les balises auto-fermantes doivent avoir une barre oblique
En JSX, les balises sans enfants doivent comporter une barre oblique de fermeture :
1// HTML
2<input type="text">
3
4// JSX
5<input type="text" />4. Toutes les balises doivent être fermées
En HTML, certaines balises peuvent rester non fermées (par exemple <img>, <br>), mais en JSX toutes les balises doivent être correctement fermées :
1// Invalide en JSX
2<img src="logo.png">
3
4// Valide en JSX
5<img src="logo.png" />5. L'élément doit être enveloppé dans un seul élément parent
JSX exige de renvoyer un seul élément parent. Si tu veux renvoyer plusieurs éléments, tu dois les envelopper dans un conteneur :
1// Invalide en JSX
2function Component() {
3 return (
4 <h1>Title</h1>
5 <p>Paragraph</p>
6 );
7}
8
9// Valide en JSX
10function Component() {
11 return (
12 <div>
13 <h1>Title</h1>
14 <p>Paragraph</p>
15 </div>
16 );
17}Si tu ne veux pas introduire d'élément DOM supplémentaire, tu peux utiliser un Fragment :
1function Component() {
2 return (
3 <>
4 <h1>Title</h1>
5 <p>Paragraph</p>
6 </>
7 );
8}6. Du JavaScript dans le JSX
Tu peux utiliser des expressions JavaScript dans le JSX en les plaçant entre accolades {} :
1function Greeting({ user }) {
2 return (
3 <div>
4 {/* Expression conditionnelle */}
5 {user ? <h1>Welcome, {user.name}!</h1> : <h1>Welcome, stranger!</h1>}
6
7 {/* Effectuer des calculs */}
8 <p>Your account was created {calculateDaysAgo(user.createdAt)} days ago</p>
9
10 {/* Parcourir une liste */}
11 <ul>
12 {user.hobbies.map(hobby => (
13 <li key={hobby.id}>{hobby.name}</li>
14 ))}
15 </ul>
16 </div>
17 );
18}Techniques JSX avancées
Opérateurs de décomposition (spread) pour les props
Tu peux utiliser l'opérateur de décomposition (...) pour passer toutes les propriétés d'un objet en tant que props :
1const buttonProps = {
2 type: 'submit',
3 disabled: false,
4 className: 'primary-button'
5};
6
7<button {...buttonProps}>Submit</button>Attributs dynamiques
Tu peux déterminer dynamiquement les attributs d'un élément :
1const inputType = isPassword ? 'password' : 'text';
2<input type={inputType} />Rendu conditionnel
JSX offre plusieurs façons de rendre des éléments de manière conditionnelle :
1// 1. Utilisation de l'opérateur ternaire
2{isLoggedIn ? <UserProfile /> : <LoginButton />}
3
4// 2. Utilisation de l'opérateur logique &&
5{isLoggedIn && <WelcomeMessage />}
6
7// 3. Utilisation d'une variable
8let button;
9if (isLoggedIn) {
10 button = <LogoutButton />;
11} else {
12 button = <LoginButton />;
13}
14return <div>{button}</div>;Styles inline
En JSX, les styles inline sont définis comme des objets JavaScript :
1const divStyle = {
2 color: 'blue',
3 backgroundColor: 'lightgray',
4 padding: '10px',
5 // Note que les propriétés comportant des tirets (comme background-color)
6 // s'écrivent en camelCase (backgroundColor)
7};
8
9<div style={divStyle}>Styled text</div>
10
11// Ou directement dans le JSX
12<div style={{ fontWeight: 'bold', fontSize: '16px' }}>Bold text</div>Commentaires dans le JSX
Les commentaires en JSX sont placés entre accolades et utilisent la syntaxe des commentaires JavaScript :
1<div>
2 {/* Ceci est un commentaire en JSX */}
3 <h1>Title</h1>
4 {/*
5 Tu peux aussi utiliser
6 des commentaires sur plusieurs lignes
7 */}
8</div>Pièges courants du JSX
1. Rendu de valeurs booléennes
JSX ne rend pas les valeurs booléennes, null et undefined :
1// Ces expressions n'affichent rien à l'écran
2<div>{true}</div>
3<div>{false}</div>
4<div>{null}</div>
5<div>{undefined}</div>
6
7// Mais les nombres et les chaînes sont rendus
8<div>{0}</div>
9<div>{"string"}</div>2. Confondre les guillemets et les accolades
N'oublie pas que les guillemets servent pour les valeurs de type chaîne et les accolades pour les expressions JavaScript :
1// Correct
2<input type="text" maxLength={10} />
3
4// Incorrect
5<input type={text} maxLength="10" /> // erreur : 'text' is not defined3. Tenter d'utiliser if/else directement dans le JSX
Tu ne peux pas utiliser d'instructions if/else directement dans le JSX, car JSX est une expression, pas une instruction :
1// Incorrect
2<div>
3 {if (isLoggedIn) {
4 return <UserProfile />;
5 } else {
6 return <LoginButton />;
7 }}
8</div>
9
10// Correct - utilise l'opérateur ternaire
11<div>
12 {isLoggedIn ? <UserProfile /> : <LoginButton />}
13</div>Résumé
JSX est l'un des aspects les plus importants de React, qui simplifie grandement la création d'interfaces utilisateur. Grâce à JSX, tu peux :
- Écrire la structure de l'UI d'une façon ressemblant au HTML
- Combiner le balisage avec la logique JavaScript
- Créer des composants lisibles et faciles à maintenir
- Exploiter toute la puissance de JavaScript pour le rendu dynamique de contenu
N'oublie pas que JSX n'est qu'une syntaxe transformée en simples appels de fonctions : React.createElement() ou, avec la nouvelle transformation, jsx() de react/jsx-runtime. Comprendre les règles et les capacités du JSX est essentiel pour programmer efficacement en React.
Code de cette leçon : App.jsx
1import React, { useState } from 'react';
2
3// Démonstration des différents aspects de JSX
4export default function App() {
5 const [count, setCount] = useState(0);
6 const [showAdvanced, setShowAdvanced] = useState(false);
7
8 // Variables utilisées dans le JSX
9 const userName = "Explorateur cosmique";
10 const currentDate = new Date().toLocaleDateString('fr-FR');
11 const items = ['Carte de la galaxie', 'Boussole quantique', 'Scanner de vie'];
12 const isLoggedIn = true;
13
14 // Styles sous forme d'objet JavaScript
15 const headerStyle = {
16 background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
17 padding: '30px',
18 borderRadius: '16px',
19 color: 'white',
20 textAlign: 'center',
21 marginBottom: '30px'
22 };
23
24 return (
25 <div style={{
26 fontFamily: 'Arial, sans-serif',
27 maxWidth: '900px',
28 margin: '0 auto',
29 padding: '20px',
30 backgroundColor: '#0a0a1a',
31 minHeight: '100vh',
32 color: 'white'
33 }}>
34 {/* Commentaire dans le JSX */}
35 <header style={headerStyle}>
36 <h1 style={{ margin: 0 }}>JSX en action</h1>
37 <p style={{ margin: '10px 0 0 0', opacity: 0.9 }}>
38 Découvre la syntaxe JSX - le cœur de React
39 </p>
40 </header>
41
42 {/* Expressions JavaScript dans le JSX */}
43 <section style={{
44 backgroundColor: '#1a1a2e',
45 padding: '25px',
46 borderRadius: '12px',
47 marginBottom: '20px'
48 }}>
49 <h2 style={{ color: '#00d4ff', marginTop: 0 }}>
50 Expressions JavaScript dans le JSX
51 </h2>
52 <div style={{ display: 'grid', gap: '15px' }}>
53 <div style={{ padding: '15px', backgroundColor: '#252545', borderRadius: '8px' }}>
54 <code style={{ color: '#888' }}>{'{'} userName {'}'}</code>
55 <p style={{ margin: '10px 0 0 0' }}>Résultat : <strong>{userName}</strong></p>
56 </div>
57 <div style={{ padding: '15px', backgroundColor: '#252545', borderRadius: '8px' }}>
58 <code style={{ color: '#888' }}>{'{'} 2 + 2 {'}'}</code>
59 <p style={{ margin: '10px 0 0 0' }}>Résultat : <strong>{2 + 2}</strong></p>
60 </div>
61 <div style={{ padding: '15px', backgroundColor: '#252545', borderRadius: '8px' }}>
62 <code style={{ color: '#888' }}>{'{'} currentDate {'}'}</code>
63 <p style={{ margin: '10px 0 0 0' }}>Résultat : <strong>{currentDate}</strong></p>
64 </div>
65 </div>
66 </section>
67
68 {/* Rendu conditionnel */}
69 <section style={{
70 backgroundColor: '#1a1a2e',
71 padding: '25px',
72 borderRadius: '12px',
73 marginBottom: '20px'
74 }}>
75 <h2 style={{ color: '#00d4ff', marginTop: 0 }}>
76 Rendu conditionnel
77 </h2>
78
79 {/* Opérateur && */}
80 {isLoggedIn && (
81 <div style={{
82 padding: '15px',
83 backgroundColor: '#4caf50',
84 borderRadius: '8px',
85 marginBottom: '15px'
86 }}>
87 Tu es connecté en tant que : {userName}
88 </div>
89 )}
90
91 {/* Opérateur ternaire */}
92 <div style={{
93 padding: '15px',
94 backgroundColor: count > 5 ? '#ff9800' : '#2196f3',
95 borderRadius: '8px'
96 }}>
97 {count > 5 ? 'Le compteur est élevé !' : 'Le compteur est bas'}
98 <div style={{ marginTop: '10px' }}>
99 <button
100 onClick={() => setCount(count + 1)}
101 style={{
102 padding: '8px 16px',
103 marginRight: '10px',
104 backgroundColor: '#4caf50',
105 color: 'white',
106 border: 'none',
107 borderRadius: '4px',
108 cursor: 'pointer'
109 }}
110 >
111 +1 (actuel : {count})
112 </button>
113 <button
114 onClick={() => setCount(0)}
115 style={{
116 padding: '8px 16px',
117 backgroundColor: '#f44336',
118 color: 'white',
119 border: 'none',
120 borderRadius: '4px',
121 cursor: 'pointer'
122 }}
123 >
124 Reset
125 </button>
126 </div>
127 </div>
128 </section>
129
130 {/* Parcours de listes (map) */}
131 <section style={{
132 backgroundColor: '#1a1a2e',
133 padding: '25px',
134 borderRadius: '12px',
135 marginBottom: '20px'
136 }}>
137 <h2 style={{ color: '#00d4ff', marginTop: 0 }}>
138 Rendu de listes avec .map()
139 </h2>
140 <ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>
141 {items.map((item, index) => (
142 <li key={index} style={{
143 padding: '12px 15px',
144 backgroundColor: '#252545',
145 borderRadius: '8px',
146 marginBottom: '10px',
147 display: 'flex',
148 alignItems: 'center',
149 gap: '10px'
150 }}>
151 <span style={{
152 width: '30px',
153 height: '30px',
154 backgroundColor: '#667eea',
155 borderRadius: '50%',
156 display: 'flex',
157 alignItems: 'center',
158 justifyContent: 'center',
159 fontWeight: 'bold'
160 }}>
161 {index + 1}
162 </span>
163 {item}
164 </li>
165 ))}
166 </ul>
167 </section>
168
169 {/* Afficher/masquer les exemples avancés */}
170 <button
171 onClick={() => setShowAdvanced(!showAdvanced)}
172 style={{
173 width: '100%',
174 padding: '15px',
175 backgroundColor: '#667eea',
176 color: 'white',
177 border: 'none',
178 borderRadius: '8px',
179 cursor: 'pointer',
180 fontSize: '16px',
181 fontWeight: 'bold'
182 }}
183 >
184 {showAdvanced ? 'Masquer' : 'Afficher'} les exemples avancés
185 </button>
186
187 {showAdvanced && (
188 <section style={{
189 backgroundColor: '#1a1a2e',
190 padding: '25px',
191 borderRadius: '12px',
192 marginTop: '20px'
193 }}>
194 <h2 style={{ color: '#ff9800', marginTop: 0 }}>
195 JSX avancé
196 </h2>
197 <div style={{
198 backgroundColor: '#252545',
199 padding: '15px',
200 borderRadius: '8px',
201 fontFamily: 'monospace',
202 fontSize: '14px',
203 lineHeight: '1.6'
204 }}>
205 <div style={{ color: '#888' }}>// Fragment - regroupement sans DOM supplémentaire</div>
206 <div style={{ color: '#61dafb' }}>{'<>'}</div>
207 <div style={{ color: '#ce9178', paddingLeft: '20px' }}>{' <Element1 />'}</div>
208 <div style={{ color: '#ce9178', paddingLeft: '20px' }}>{' <Element2 />'}</div>
209 <div style={{ color: '#61dafb' }}>{'</>'}</div>
210 </div>
211 </section>
212 )}
213 </div>
214 );
215}Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Quelle est l'une des règles clés de la syntaxe JSX ?
Tâches pratiques dans le jeu
- Tri horizontal
Ordonne la syntaxe correcte d'un élément JSX, de gauche à droite :
- Éditeur de code
Crée un ControlPanel avec : un titre h1 'Panneau de contrôle', une liste <ul> de 3 systèmes (avec map), et un bouton 'Activer' avec onClick. Utilise className pour la stylisation.
- Éditeur de code
Sans JSX : dans le composant App, utilise React.createElement pour créer un élément du composant SpaceshipPart avec les propriétés name et type (par ex. name: 'Moteur', type: 'propulsion') et renvoie-le. SpaceshipPart doit afficher le nom et le type de la pièce.
- Clique dans l'ordre
Construis une expression JavaScript correcte intégrée dans un élément JSX :
- Tri horizontal
Ordonne la syntaxe de React.createElement pour créer un élément h1 avec du texte :
- Tri horizontal
Ordonne la syntaxe pour rendre le composant App dans le DOM dans main.jsx (React 18+) :
- Éditeur de code
Crée un composant CrewMembers qui renvoie plusieurs éléments (par ex. un <li> par membre d'équipage) regroupés dans un Fragment (<></> ou <React.Fragment>) au lieu d'un <div> supplémentaire.
- Tri vertical
Ordonne le processus de compilation du JSX jusqu'au DOM :
- Éditeur de code
Enveloppe le composant principal App dans React.StrictMode pour activer des vérifications supplémentaires pendant le développement.
- Tri horizontal
Ordonne la syntaxe d'import correcte de la bibliothèque ReactDOM pour le rendu dans le navigateur :
- Éditeur de code
Utilise ReactDOM.createRoot pour rendre le composant SpaceStation dans l'élément du DOM ayant l'id 'space-station' (comme dans le fichier main.jsx de la leçon sur Vite).
- Éditeur de code
Crée un composant SystemStatus qui accepte des props : {name, status, power}. Affiche : le nom du système, le statut (online/offline) et la consommation d'énergie.
- Tri horizontal
Ordonne la syntaxe d'import correcte de la bibliothèque React :