Composants et JSX
Une interface, c'est une fonction qui reçoit des données et renvoie ce qu'il faut afficher.
Objectifs de la séance
- comprendre ce qu'est un composant et ce qu'est le JSX ;
- insérer des valeurs dans le JSX avec les accolades
{ }; - transmettre des données à un composant avec les props ;
- afficher une liste avec
mapet la propriétékey; - afficher un élément seulement si une condition est vraie, sans piège.
Notions théoriques
Un composant, c'est une fonction
Dans une application Expo, chaque morceau d'écran est un composant : une simple fonction qui renvoie ce qu'il faut afficher. Cette description s'écrit en JSX, une syntaxe qui ressemble beaucoup au HTML.
import { Text, View } from "react-native";
export default function App() {
return (
<View>
<Text>Bonjour le quiz !</Text>
</View>
);
}
Vous reconnaissez tout ce que vous avez appris : une fonction, return, export default (obligatoire pour un écran), des parenthèses autour du retour sur plusieurs lignes.
Les briques de React Native
En HTML, vous utilisiez <div>, <p>, <button>. En React Native (Expo), les briques ont d'autres noms :
| HTML | React Native | Rôle |
|---|---|---|
<div> | <View> | conteneur |
<p>, <span>, <h1> | <Text> | tout texte |
<button> | <Pressable> | zone sur laquelle on appuie |
<img> | <Image> | image |
Contrairement au HTML, un texte écrit directement dans un <View> provoque une erreur (« Text strings must be rendered within a <Text> component »). Tout texte, même un nombre, doit être placé dans un <Text>.
Insérer des valeurs avec { }
Dans le JSX, les accolades permettent d'insérer n'importe quelle expression JavaScript (variable, calcul, appel de fonction).
const joueur = "Alice";
const score = 7;
<Text>Bravo {joueur} ! Votre score : {score * 10} points</Text>
Les accolades ne servent pas à écrire des instructions (if, for) : seulement des expressions (valeurs).
Les règles du JSX
- un composant renvoie un seul élément racine (enveloppez plusieurs éléments dans un
<View>ou un fragment<>...</>) ; - toute balise doit être fermée :
<Text>...</Text>ou<Image />; - le nom d'un composant commence par une majuscule (
CarteQuestion), pour le distinguer des balises natives ; - les attributs sont écrits en
camelCase, et un objet de style prend deux paires d'accolades :style={{ padding: 8 }}.
Les styles
Les styles ne s'écrivent pas en CSS mais en objets JavaScript, regroupés avec StyleSheet.create.
import { StyleSheet, Text, View } from "react-native";
<View style={styles.carte}>
<Text style={styles.titre}>Quiz Cyber</Text>
</View>
const styles = StyleSheet.create({
carte: { backgroundColor: "white", padding: 16, borderRadius: 8 },
titre: { fontSize: 24, fontWeight: "bold" },
});
Les noms sont en camelCase (backgroundColor, pas background-color) et les valeurs numériques n'ont pas d'unité.
Les props : donner des données à un composant
Un composant devient réutilisable quand on lui transmet des données, qu'il reçoit dans un objet appelé props. Vous reconnaissez la destructuration de paramètres de la partie 3.
type CarteQuestionProps = {
enonce: string;
niveau: number;
};
function CarteQuestion({ enonce, niveau }: CarteQuestionProps) {
return (
<View>
<Text>{enonce}</Text>
<Text>Niveau {niveau}</Text>
</View>
);
}
// Utilisation : les props s'écrivent comme des attributs
<CarteQuestion enonce="À quoi sert un VPN ?" niveau={2} />
Les props sont en lecture seule : un composant ne modifie jamais ses props (comme une fonction pure ne modifie pas ses arguments). Pour un texte, on écrit enonce="..." ; pour tout le reste (nombre, variable, booléen), on utilise les accolades : niveau={2}.
Afficher une liste : map et key
Pour afficher un tableau, on utilise map (partie 3) qui transforme chaque donnée en composant.
{questions.map((question) => (
<CarteQuestion
key={question.id}
enonce={question.enonce}
niveau={question.niveau}
/>
))}
La propriété key est obligatoire : elle permet à React d'identifier chaque élément quand la liste change. Elle doit être unique et stable, comme l'id de la donnée.
N'utilisez pas l'indice du tableau (key={index}) quand la liste peut être modifiée, triée ou filtrée : React s'y perdrait et pourrait afficher des données mélangées. Utilisez l'id.
Afficher selon une condition
Deux écritures pour afficher un élément seulement si une condition est vraie :
{indice ? <Text>Indice : {indice}</Text> : null} // ternaire : sûre, claire
{estTerminee && <Text>Partie terminée</Text>} // && : pratique, mais avec un piège
{nombre && <Text>...</Text>} : si nombre vaut 0, JavaScript renvoie 0... et React Native tente d'afficher un 0 en dehors d'un <Text>, ce qui fait planter l'écran.
Utilisez un ternaire (nombre > 0 ? <Text>...</Text> : null) ou une condition booléenne claire (nombre > 0 && ...).
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Votre mission : afficher la liste des questions du quiz sous forme de cartes. Dans Expo Snack, remplacez le contenu de App.tsx au fil des étapes.
Point de départ :
import { StyleSheet, Text, View } from "react-native";
type Question = {
id: number;
enonce: string;
niveau: 1 | 2 | 3;
indice?: string;
};
const questions: Question[] = [
{ id: 1, enonce: "Quel mot de passe est le plus robuste ?", niveau: 1, indice: "Pensez à la longueur" },
{ id: 2, enonce: "Qu'est-ce que l'hameçonnage ?", niveau: 1 },
{ id: 3, enonce: "À quoi sert un VPN ?", niveau: 2 },
];
Étape 1 — Définir les props d'une carte
Décrivez les props de CarteQuestion : l'énoncé, le niveau, et un indice facultatif.
Décrire les props avec un type nommé (CarteQuestionProps) documente le composant : en lisant ce type, on sait ce qu'il faut lui donner.
Étape 2 — Écrire le composant
Écrivez l'ouverture du composant avec la destructuration des props.
CarteQuestion commence par une majuscule : React reconnaît ainsi un composant et ne le confond pas avec une balise native.
Étape 3 — Afficher la liste
Dans App, affichez une carte par question.
La key se place sur l'élément le plus extérieur renvoyé par le map (ici CarteQuestion), pas dans un composant enfant.
Étape 4 — Afficher l'indice seulement s'il existe
Dans CarteQuestion, ajoutez une ligne d'indice uniquement quand indice est renseigné.
null ne s'affiche pas. Avec un ternaire, vous ne risquez jamais d'afficher par erreur un 0 ou un texte vide hors d'un <Text>.
📌 Une solution
Ce qu'il faut retenir
| Notion | Résumé |
|---|---|
| Composant | Fonction (nom en majuscule) qui renvoie du JSX ; un écran est un export default. |
| JSX | Syntaxe proche du HTML ; { } insère une expression JavaScript ; tout texte dans un <Text>. |
| Briques | View (conteneur), Text (texte), Pressable (appui), Image. |
| Props | Données reçues du parent, en lecture seule, décrites par un type et destructurées. |
| Listes | liste.map((x) => <Composant key={x.id} ... />) avec une key unique et stable. |
| Condition | condition ? <A /> : null ; attention à && avec un nombre (le 0 plante). |
Aperçu de la prochaine séance
Votre écran est joli, mais figé. Dans la prochaine séance, vous allez le rendre vivant : un bouton, un score qui augmente, un écran qui se met à jour tout seul grâce à useState.
Vous y retrouverez la destructuration de tableau, les fermetures et la règle « ne jamais modifier, toujours copier ».