Laboratoire 1: Découverte de JSX et de React
Introduction
JSX est une extension de JavaScript développée par Facebook. Il permet de créer des composants avec le balisage HTML classique en y rajoutant la flexibilité qu’apporte JavaScript. L’idée est de rassembler le rendu du composant avec sa logique. Le but est ainsi d’avoir des composants "autonomes" et réutilisables entre différents projets. Ce labo a pour but de présenter les fonctionnalités du JSX pour pouvoir utiliser plus facilement React. Même si les captures d’écran sont faites sur Windows, ce labo peut aussi être suivi sur Linux et Mac, car les outils nécessaires sont multiplateformes.
Environnement de développement
La première étape consiste à vérifier que NodeJS est installé sur le système. En effet, nous avons besoin de son package manager (NPM) et de NodeJS pour transformer le JSX en JavaScript classique lisible par n’importe quel navigateur. Pour cela, il faut taper la commande suivante dans un terminal :
node --version
Si vous voyez un numéro de version, c’est que NodeJS est installé. Sinon, il faut passer par le site officiel pour télécharger NodeJS. Etant donné qu’il s’agit d’un environnement de DEVELOPEMENT, nous pouvons utiliser la version qui ne comporte pas « LTS » (dans un environnement de PRODUCTION il FAUT utiliser la version LTS !).
Vite est un outil particulièrement pratique pour la création d'applications frontend dont React. Pour utiliser Vite, il suffit d'utiliser la commande suivante:
npm create vite@latest laboratoire_1 -- --template react
Ensuite exécutez la commande suivante:
npm install
Une fois la commande exécutée, rendez-vous dans le dossier laboratoire_1 et ouvrez un terminal pour exécuter la commande suivante:
npm run dev
Vous verrez un lien dans votre terminal. Copiez-le dans la barre d'adresse de votre navigateur et vous devriez arriver sur cette page.

Maintenant, nous allons pouvoir essayer notre première modification ! Ouvrez le fichier ./src/App.js et remplacez le texte par "Hello World" comme dans le code suivant :
import './App.css'
function App() {
return (
<div className="App">
<p>Hello World !</p>
</div>
)
}
export default App
Sauvegardez et revenez sur le navigateur. Vous verrez que la page a été modifiée sans la rafraichir, grâce au "hot reloading" qu’offre Vite (ce qui facilite le développement).
Premiers pas
La force de JSX est qu’il permet d’utiliser JavaScript pour interpréter des valeurs. Par exemple, il est possible d’appeler des fonctions JavaScript. Pour cela, il faut utiliser les {} qui indique au compilateur qu’il s’agit de code JavaScript et d’utiliser la valeur de retour. Par exemple :
import './App.css'
function App() {
return (
<div className="App">
<p>{"Hello World !".toUpperCase()}</p>
</div>
)
}
export default App
Dans ce cas, la chaîne de caractères "Hello World" est un string sur lequel on appelle la méthode toUpperCase. Cette méthode renvoie la chaîne de caractères en majuscule. C’est cette valeur qui sera utilisée.
Etant donné qu’il s’agit d’un fichier JS, il est tout à fait possible de créer des méthodes et de les appeler :
import './App.css'
function add_smiley(string){
return string.trim() + " :)"
}
function App() {
return (
<div className="App">
<p>{"Hello World !".toUpperCase()}</p>
<p>{add_smiley("Bonjour tout le monde !")}</p>
</div>
)
}
export default App
Il est donc aussi possible de travailler avec des variables :
import './App.css'
let tmp = "Hello World"
function add_smiley(string){
return string.trim() + " :)"
}
function App() {
return (
<div className="App">
<p>{tmp.toUpperCase()}</p>
<p>{add_smiley("Bonjour tout le monde !")}</p>
</div>
)
}
export default App
Les attributs définis dans les balises sont utilisés tels quels dans le rendu HTML (src, alt,…). Attention, il existe des exceptions comme className qui sera rendu en class.
Il est très important de noter que les balises HTML commencent par une minuscule tandis qu’un composant devra commencer par une majuscule !
Pour vous en rendre compte, ouvrez le fichier src/main.jsx. Vous verrez que la "balise" App commence par une majuscule, car il s’agit du composant App et non d’une balise HTML App. Si vous remplacez App par app, vous aurez une page blanche. En regardant le code HTML, vous verrez ceci :

Ce qui explique la page blanche. Remettez la majuscule et tout rentrera dans l’ordre.
Enfin, il existe une dernière règle de base assez simple:
Un composant (comme « App ») doit toujours avoir une seule balise parente !
Actuellement, il s’agit de la balise div. Si nous en rajoutons une nouvelle comme ici :
import './App.css'
let tmp = "Hello World"
function add_smiley(string){
return string.trim() + " :)"
}
function App() {
return (
<div className="App">
<p>{tmp.toUpperCase()}</p>
<p>{add_smiley("Bonjour tout le monde !")}</p>
</div>
<div></div>
)
}
export default App

Vous pouvez utiliser des balises "vides" pour avoir une balise parente ! Il vous suffit d'entourer votre code avec des <><>. Il s'agit d'un raccourci pour les Fragments qui permettent d'éviter de rajouter des <div> partout !
Il est temps de passer aux notions plus avancées !
JSX avancé
Etant donné que nous utilisons JavaScript, il est possible de faire du rendu conditionnel ! Par exemple avec le code suivant :
import './App.css'
const response = {
error: true,
message: "L'api ne répond plus"
}
function App() {
return (
<div className="App">
{
response.error ? (
<p>Une erreur est survenue: {response.message}</p>
) : <p>Hello World !</p>
}
</div>
)
}
export default App
Ici, nous utilisons l’opérateur ternaire pour indiquer : Si la valeur de reponse.error est true, alors il faut afficher le message d’erreur, sinon on affiche le message de bienvenue. Pour vous en assurer, changez error : true par error : false.
Nous avons aussi la possibilité de mettre du code JSX dans des variables et d'ensuite les utiliser:
import './App.css'
const response = {
error: true,
message: "L'api ne répond plus"
}
function App() {
const contenu = response?.error ?
<p>Une erreur est survenue: {response.message}</p> :
<p>Hello World</p>
return (
<div className="App">
{contenu}
</div>
)
}
export default App
Cette approche permet aussi quelque chose de très intéressant. On dissocie la partie "logique" de la partie "rendu" qui est censée être simple. Dans le cas d’une condition simple, on peut très bien utiliser une condition ternaire (ex : afficher le nom de la personne si elle est connectée, sinon on n’affiche rien), mais dans des cas plus compliqués, il est conseillé de séparer la logique du rendu HTML.
Il existe aussi une autre façon d’afficher un élément de manière conditionnelle. Imaginons que l’on souhaite afficher un composant seulement si une condition est vérifiée. JSX nous propose la solution suivante : condition && composant. Par exemple :
import './App.css'
const estConnecte = true;
function App() {
return (
<div className="App">
{
(estConnecte === true) && <p>Vous êtes connectés</p>
}
</div>
)
}
export default App
Nous verrons le paragraphe "Vous êtes connectés", car la condition est vérifiée. Si nous changeons la variable en false, nous ne verrons plus ce paragraphe.
Un autre point intéressant est la possibilité de faire des boucles. Il est possible de renvoyer le même code HTML pour un ensemble d’éléments. Supposons que nous avons une liste de produits avec un nom et un prix. Il est tout à fait possible de construire une liste HTML rapidement avec une fonction map. Nous allons utiliser le code suivant :
import './App.css'
const produits = [
{
nom: "Pomme",
prix: 0.5
},
{
nom: "Poire",
prix: 2.5
},
{
nom: "Abricot",
prix: 3
}
];
function App() {
return (
<div className="App">
<ul>
{produits.map(p => {
return <li>{p.nom} à {p.prix} euro(s)</li>
})}
</ul>
</div>
)
}
export default App
Il est important de noter que si nous nous retrouvons avec une liste d’éléments, il est conseillé d’utiliser l’attribut key et lui donner une valeur unique propre à chaque élément. En effet, React utilise un système de clés dans les listes pour pouvoir plus facilement retrouver les éléments à enlever ou à mettre à jour.
Les composants
React recommande depuis plusieurs années d'utiliser les Hooks au lieu des Composants. Cette partie n'aura pour but que de vous apprendre comment fonctionne les composants sous forme de classe. En effet, vous aurez beaucoup de chance de rencontrer du code "legacy" dans votre futur métier !
Pour votre projet, vous n'aurez pas le choix: l'utilisation des Hooks sera obligatoire !
Les composants React sont des composants réutilisables et paramétrables. C’est tout l’intérêt des composants, comme nous l’avons vu au cours. Pourquoi réécrire le code d’un tableau plusieurs fois alors qu’il n’y a que les données à l’intérieur qui changent. C’est en cela que les composants sont utiles. Prenons un exemple avec un tableau justement : je souhaite afficher une liste de produits avec les informations suivantes : nom, catégorie et prix.
import React from 'react'
class MonTableau extends React.Component {
constructor(props){
super(props);
this.state = {};
this.state.produits = [
{nom: "Pomme", prix: 0.50, categorie: "Fruit"},
{nom: "Fromage", prix: 2.50, categorie: "Produit laitier"},
{nom: "Pancakes", prix: 2.19, categorie: "Crèmerie"}
]
}
render(){
return(
<table>
<tr>
<th>Nom</th>
<th>Prix</th>
<th>Catégorie</th>
</tr>
{
this.state.produits.map(p => {
return (
<tr>
<td>{p.nom}</td>
<td>{p.prix}</td>
<td>{p.categorie}</td>
</tr>
)
})
}
</table>
)
}
}
export default MonTableau;
Dans cet exemple, on voit 2 grandes parties : le constructeur avec les données (qui sont dans un objet nommé state) et la partie rendue avec la méthode render(). Il est important de comprendre le lien entre ces 2 parties. Les données sont utilisées par la partie rendue pour afficher le tableau. Si on change une partie des données (dans l'état ou "state" en anglais), automatiquement un rendu sera fait (il est possible de modifier ce comportement, nous verrons cela plus tard). L'état est intéressant dès que l'on souhaite qu'un composant puisse mémoriser des informations (retenir le choix d'un utilisateur, les informations d'un formulaire, etc). Dans notre exemple, si nous rajoutions une nouvelle entrée dans le tableau, l'état du composant changerait et donc un nouveau rendu serait enclenché.
Le lien entre les deux est simple: le constructeur sert à initialiser l'état de l'objet. Cet état est "écouté" par React et à chaque modification de celui-ci, la fonction render() est appelée pour produire le code HTML associé à ce composant.
Les composants suivent un cycle de vie. En effet, un composant a plusieurs "étapes" dans sa vie (monté, démonté, mis à jour, etc). Vous pouvez implémenter des fonctions qui sont appelées lors de ces étapes de vie et ainsi charger les données correctement. Vous pouvez implémenter plusieurs méthodes comme componentDidMount(). Pour mieux visualiser les différentes méthodes, voici un diagramme :
Source
Certaines actions ne peuvent pas se faire n'importe où. Par exemple: il est INTERDIT de faire un appel réseau dans le constructeur. Pourquoi ? En regardant le graphique, on se rend compte que la méthode render() n'est enclenchée qu'après que le constructeur a terminé. En bloquant le constructeur avec un appel réseau (n'oubliez pas que les requêtes sur le net prennent du temps), vous allez bloquer la chaîne de rendu de React et donc bloquer votre SPA.
C'est pour cette raison que vous devriez initialiser votre composant avec des valeurs par "défaut" et charger les données, une fois que le composant est monté. Quand le composant est monté, la fonction componentDidMount() est appelée. C'est donc l'occasion idéale pour charger les données !
Nous n'irons pas plus loin pour cette partie. Nous verrons la gestion de l'état avec les Hooks durant le prochain laboratoire !