Cours JavaScript et React · Module 1: Bases de React

La syntaxe JSX

6 min de lecture
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 -> onClick
  • tabindex -> tabIndex
  • class -> 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 defined

3. 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. 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 :

Articles utiles