Syntaxe JSX
Introduction
Avant de commencer à parler des composants React, découvrons tranquillement la syntaxe JSX.
Le JSX est un sucre syntaxique (une syntaxe plus lisible et plus simple que le JavaScript pur) qui permet de décrire l'interface utilisateur (UI) de notre application.
Le sigle en lui-même signifie JavaScript XML, dans le sens où l'on va retrouver une syntaxe proche du XML (eXtensible Markup Language) qui est un langage de balisage (comme le HTML).
🔍 Différences entre HTML et JSX
Et oui, le JSX ressemble beaucoup au HTML et c'est normal !
C'est l'objectif premier de React : rendre la création d'interfaces utilisateur (UI) plus simple et plus intuitive.
Cependant il ne faut pas oublier que le JSX n'est pas du HTML, mais du JavaScript.
Pour faire plus simple, voici un élément HTML et son équivalent avec React (avec et sans JSX) :
- HTML
- React sans JSX
- React avec JSX
<button class="button">Clique moi !</button>
React.createElement('button', { className: 'button' }, 'Clique moi !');
<button className="button">Clique moi !</button>
Comme tu peux le constater, la différence entre le JSX et le HTML est minime.
Il y a toutefois des différences, comme certains mots réservés (comme class
qui devient className
) ou encore la manière de déclarer des événements (comme onclick
qui devient onClick
).
Par contre si on regarde la différence entre le JSX et le JavaScript pur (en utilisant React quand même), on voit bien que le JSX est beaucoup plus lisible et plus simple à écrire.
Là où c'est encore plus flagrant, c'est quand on commence à imbriquer des éléments (comme des composants React par exemple) !
- React sans JSX
- React avec JSX
React.createElement(React.Fragment, null,
React.createElement('h2', null, 'Formulaire de contact'),
React.createElement('form', { onSubmit: handleSubmit },
React.createElement('fieldset', null,
React.createElement('label', { htmlFor: 'lastname' }, 'Nom'),
React.createElement('input', { type: 'text', name: 'lastname', id: 'lastname', required: true })
),
React.createElement('fieldset', null,
React.createElement('label', { htmlFor: 'email' }, 'Email'),
React.createElement('input', { type: 'email', name: 'email', id: 'email', required: true })
),
React.createElement('fieldset', null,
React.createElement('label', { htmlFor: 'message' }, 'Message'),
React.createElement('textarea', { name: 'message', id: 'message', required: true })
),
React.createElement('fieldset', null,
React.createElement('label', { htmlFor: 'gdpr' },
React.createElement('input', { type: 'checkbox', name: 'gdpr', id: 'gdpr', required: true }),
'J\'accepte que mes données soient utilisées pour me recontacter'
)
),
React.createElement('button', { type: 'submit' }, 'Envoyer')
)
);
<React.Fragment>
<h2>Formulaire de contact</h2>
<form onSubmit={handleSubmit}>
<fieldset>
<label htmlFor="lastname">Nom</label>
<input type="text" name="lastname" id="lastname" required>
</fieldset>
<fieldset>
<label for="email">Email</label>
<input type="email" name="email" id="email" required>
</fieldset>
<fieldset>
<label for="message">Message</label>
<textarea name="message" id="message" required></textarea>
</fieldset>
<fieldset>
<label for="gdpr">
<input type="checkbox" name="gdpr" id="gdpr" required>
J'accepte que mes données soient utilisées pour me recontacter
</label>
</fieldset>
<button type="submit">Envoyer</button>
</form>
</React.Fragment>
Et bien même si le code final est identique, le JSX apporte une lisibilité et une simplicité d'écriture qui est très appréciable. Pas mal non ? 😄
Et donc oui ! En faisant du JSX, on fait en réalité du JavaScript et pas du HTML !
Au sein de ses pages, tu verras toujours que j'importe le contenu de React en intégralité (comme import React from 'react';
).
Dans la réalité, on va destructurer les exports de React pour n'importer que ce dont on a besoin.
Cependant, pour te donner l'information d'où provient chaque élément, je préfère importer React en intégralité et que tu puisses visualiser les éléments de React utilisés avec leur provenance.
Par exemple, cela donnerait :
import React from 'react';
const [count, setCount] = React.useState(0);
Au lieu de :
import { useState } from 'react';
const [count, setCount] = useState(0);
Pour tes projets, privilégies la seconde méthode pour ne pas surcharger ton code inutilement et surtout importer seulement ce dont tu as besoin !
J'espère que tu comprends mieux pourquoi je fais comme ça pour ces ressources 😉
🧩 Intégration de JavaScript dans le JSX
Mais l'un des autres avantages du JSX est la possibilité d'ajouter du JavaScript directement dans le code !
Pour pouvoir ajouter du JavaScript dans le JSX, il suffit d'entourer le code JavaScript avec des accolades {}
.
C'est un peu comme si on "ouvrait un portail" pour insérer du JavaScript dans notre code JSX.
📦 Variables et fonctions
Par exemple, si tu veux afficher une variable dans ton JSX, tu peux le faire directement :
const name = 'Jean Dupont';
return <h1>Bonjour {name} !</h1>;
Et si tu veux appeler une fonction, c'est tout aussi simple :
const sayHello = () => 'Bonjour !';
return <p>{sayHello()}</p>;
📝 Expressions
Tu peux également ajouter des expressions (comme des conditions ternaires par exemple) :
const age = 18;
return <p>{age >= 18 ? 'Majeur' : 'Mineur'}</p>;
Mais tu peux aussi faire un affichage conditionnel de manière très simple :
const isLogged = false;
return (
<div>
{isLogged && <p>Bienvenue sur notre site !</p>}
{!isLogged && <p>Connectez-vous pour accéder à notre site</p>}
</div>
);
🔄️ Boucles
Maintenant imagine que tu souhaites créer une interface qui liste des éléments provenant d'un tableau.
const fruits = ['pomme', 'banane', 'fraise'];
Dans un premier temps, on va revoir très rapidement comment on peut parser un tableau en JavaScript :
for
:for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}forEach
:fruits.forEach((fruit) => console.log(fruit));
map
:fruits.map((fruit) => console.log(fruit));
- et bien d'autres encore...
En soit, toutes ces méthodes sont très bien et font ce qu'on leur demande sans souci.
Cependant, React ne va pas forcément aimer ça sauf pour map
.
La raison est simple :
React a besoin qu'on lui retourne un élément (ou un tableau d'éléments) pour pouvoir les afficher.
Alors avec des console.log
on ne va pas aller loin, mais si au lieu de retourner un console.log
on retournait un élément JSX ? 🤔
const fruits = ['pomme', 'banane', 'fraise'];
return (
<ul>
{fruits.map((fruit) => <li key={fruit}>{fruit}</li>)}
</ul>
);
🕹️ Voir l'exemple sur PlayCode
Et là : BAM ! 💥
Tu viens de créer une liste de fruits en utilisant un tableau de fruits.
Mais par contre...
La key
est une propriété spéciale que React utilise pour identifier chaque élément de manière unique.
Cela permet à React de savoir quel élément a été ajouté, modifié ou supprimé.
Il est obligatoire d'avoir une key
unique pour chaque élément d'une liste.
Si tu listes des éléments qui ont un identifiant unique (comme l'id
qu'on aura dans nos données stockées dans une base de données par exemple), tu peux utiliser cet identifiant comme key
.
📦 Les props
Les props (ou propriétés) sont des arguments que l'on peut passer à un composant React.
Je ne vais pas trop rentrer dans les détails ici, car on va les voir dans l'article d'après !
Mais pour te donner un aperçu, voici comment on peut passer des props à un composant :
- JSX
- TSX
const Button = (props) => {
return <button onClick={props.onClick}>{props.children}</button>;
};
type ButtonProps = {
onClick: () => void;
children: React.ReactNode;
};
const Button = (props: ButtonProps) => {
return <button onClick={props.onClick}>{props.children}</button>;
};
Ici, on a un composant Button
qui prend deux props : onClick
et children
.
onClick
est une fonction qui sera appelée lorsqu'on cliquera sur le bouton, et children
est tout ce qui se trouve entre les balises ouvrante et fermante du composant.
Conclusion
Alors, plutôt cool le JSX non ? 😎
Même si cette syntaxe rebute certains développeurs (souvent ils se la jouent puristes, mais chuuuuut 🤫), elle est toutefois très appréciée pour sa simplicité et sa lisibilité.
Question de goût après tout !