2
Module 2
Les composants et props
A la fin de ce deuxième module, l'étudiant devra être capable de créer des composants et de leur passer des données. Il devra aussi être capable d'optimiser les images ainsi que les polices de caractères de son projet.

Composants, props et enfant
Mise en situation
Pour mieux comprendre les notions de composants et props dans React, nous allons partir d'un exemple simple. Supposons que nous voulons créer une application en C# ou Java pour calculer et afficher, la moyenne des notes obtenus par des étudiants lors d'une évaluation. Pour cela, on peut décider de créer une fonction qui retourne la somme de toutes les notes, une autre fonction qui fait la division de la somme obtenue, par l'effectif total et enfin une dernière fonction qui affiche la moyenne obtenue. Il est à noter que chacune de ces fonctions pourra prendre des paramètres et retourner des résultats de différents types.
Nous savons tous que cette approche généralement appelée programmation modulaire ou procédurale, possède de nombreux avantages tels que la lisibilité du code, la réutilisation des fonctions pour éviter des répétitions inutiles et bien d'autres encore.
Vous devez donc savoir que l'idée derrière la notion de composant et de prop en React est similaire à celle des fonctions classiques. En effet, pour réaliser notre application, au lieu de créer une page ou plusieurs pages web, ayant de nombreuses sections touffues qui parfois se répètent, nous allons créer des fonctions que nous pourrons appeler pour créer ces sections. Ces fonctions seront donc appelées composants. De plus, à ces fonctions, nous pourrons passer des paramètres que nous appellerons props dans le contexte de React.
Les composants
Nous pouvons dire que les composants en React sont des unités de code permettant de découper l'interface d'une application en éléments indépendants et isolés, pouvant être réutilisés. Ces unités peuvent prendre en entrée des propriétés (ou props) et renvoyer en sortie des éléments React (généralement du JSX).
Demo
Nous allons reprendre notre application biblio-app et créer son entête ou header. Pour cela, les dossiers et fichiers suivants seront créés:
Dossier '/components' : A la racine du dossier de notre application, créer un dossier nommé 'components'. Ce dossier contiendra nos composants.
Fichier '/components/Header.jsx' : Dans le dossier '/components', créer un fichier nommé 'Header.jsx', puis ajouter le code qui va suivre. Ce fichier contiendra le définition de l'entête de notre application.
/components/Header.jsx
import styles from './Header.module.css'
export default function Header() {
return <header className={styles.header}>
        <nav className={styles.nav}>
            <ul>
                <li><a href='#'>Accueil</a></li>
                <li><a href='#'>Documents</a></li>
                <li><a href='#'>Contact</a></li>
                <li><a href='#'>Connexion</a></li>
            </ul>
        </nav>
    </header>
}
Fichier '/components/Header.module.css' : Dans le dossier '/components', créer un fichier nommé 'Header.module.css', puis ajouter le code qui va suivre. Ce fichier contiendra le CSS de Header.jsx
/components/Header.module.css
.nav ul {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 1rem;
    list-style-type: none;
    margin: 0;
    padding: 0;
}
.nav a {
    color: #fff;
    font-weight: 700;
}
.header {
    padding: 1rem;
    background-color: var(--first-color);
}
Important
Après la création de notre composant Header, il faut l'ajouter au fichier 'layout.jsx'. Pour cela, il allons lui faire les insertions suivantes
Fichier '/app/layout.jsx' : Ajouter le premier code au debut du fichier et insérer le deuxième juste après la ligne [<body className={inter.className}>]
/app/layout.jsx (premier code)
import Header from '@/components/Header'
/app/layout.jsx (deuxième code)
<Header />
Bon à savoir
Toujours penser à exécuter la commande [npm run dev] pour exécuter l'application.
Les props et enfants des composants
Nous allons à présent créer un composant Citation qui va prendre en entrée le nom de l'auteur d'une citation et retourner ladite citation ainsi que son auteur.
Fichier '/components/Citation.jsx' : Dans le dossier '/components', créer un fichier nommé 'Citation.jsx'
/components/Citation.jsx
import styles from './Citation.module.css'
export default function Citation(props) {
    return <>
        <div className={styles.citation}>
            {props.children}
        </div>
        <div className={styles.auteur}>
            - {props.auteur}
        </div>
    </>
}
Fichier '/components/Citation.module.css' : Dans le dossier '/components', créer un fichier nommé 'Citation.module.css'
/components/Citation.module.css
.citation {
    font-style: italic;
}
.auteur {
    font-weight: bold;
    margin-bottom: 1rem;
}
Fichier '/app/page.jsx' : Remplacer le code de '/app/page.jsx' par le code suivant :
/app/page.jsx
import Image from 'next/image';
import styles from './page.module.css';
import Citation from '@/components/Citation';
export default function Home() {
  return (
    <main className={styles.main}>
      <Citation auteur='Sedric'>
        Nous y sommes
      </Citation>
      <div className={styles.welcome}>
        Soyez la bienvenue sur biblio-app
      </div>
    </main>
  );
}
Remarque
Dans l'exemple précédent, {props.children} permet d'acccéder à l'enfant du composant Citation. Vous pouvez à présent vous amuser en ajoutant vos propres citations personnalisées.

Layout de base avec Next.js
Dans Next.js, un 'layout' est un modèle utilisé pour organiser les composants réutilisables et fournir une structure commune à différentes pages d'une application. En effet, dans une application web, certains composants l'instar des barres de navigation, des pieds de page et bien d'autres, se retrouvent dans toutes ou presque toutes les pages. Au lieu d'ajouter ces composants à chacune de nos pages, nous les ajouterons simplement au layout et ils apparaitrons dans nos différentes pages.
Reprenons notre fichier 'layout.jsx'
/app/layout.jsx
import Header from '@/components/Header';
import { Inter } from 'next/font/google';
import './globals.css';
const inter = Inter({ subsets: ['latin'] });
export const metadata = {
  title: 'Biblio-app',
  description: 'Demo Cours Programmation web avancé',
};
export default function RootLayout({ children }) {
  return (
    <html lang='en'>
      <body className={inter.className}>
        <Header />
        {children}
      </body>
    </html>
  );
}
Remarque
Dans notre exemple, le layout a structure de base de notre application avec un en-tête (composant </Header>), un contenu principal (où le contenu des pages s'affichera via {children}), et éventuellement un pied de page (après {children}) pour ceux qui l'ont crée.
Bon à savoir
Dans les fichiers de page, le layout est automatiquement utilisé si placé dans le bon segment. Dans notre cas par exemple, toutes les pages à l'intérieur du dossier /app utiliseront le layout précédent (layout.jsx).

Types de CSS
Plusieurs approches peuvent être utilisées pour définir le CSS dans une application React avec Next.js. Parmi ces approches, on peut citer :
global CSS : Cette approche consiste à définir un fichier css qui contiendra les styles applicable à toutes les pages de l'application. Dans notre cas, il s'agit du fichier 'global.css' qui a été présenté dans le module1. Ce fichier contient des styles tels les couleurs, les polices de caractères et bien d'autres.
Remarque
Le fichier 'globals.css' puisqu'il s'applique à toutes les pages, est évidemment importé dans le fichier 'layout.jsx'.
Tailwind CSS : C'est un framework CSS pouvant accroître le processus de mise en forme de vos pages web, grace à de nombreuses classes prédéfinies et prêtes à l'emploi. Nous n'utiliserons pas Tailwind dans le cadre ce cours, mais il serait utile d'en savoir plus'.
CSS Modules : Cette approche consiste à définir et lier un fichier CSS à un composant spécifique. C'est cette approche qui sera utilisée dans ce cours. Pour illustrer cela, nous avons précédemment défini 2 fichiers CSS à savoir : 'Header.module.css' et 'Citation.module.css' qui sont respectivement liés aux composants 'Header.jsx' et 'Citation.jsx'.
la bibliothèque clsx : C'est une petite bibliothèque qui permet d'affecter différentes classes à un élément HTML à partir de certaines conditions préétablies.
Bon à savoir
Dans le cadre de ce cours, nous utiliserons majoritairement les modules CSS.

Polices de caractères optimisées dans Next.js
Pourquoi optimiser les polices de caractères ou fonts?
Les polices de caractères affectent considérablement les perfomances d'une application web. Pour cette raison, nous devons leur porter une attention particulière. A cet sujet, Next.js a prévu de faire le travail pour nous en optimisant automatiquement nos polices de caractères, mais à condition que nous utilisons les polices du module next/font
Comment cela fonctionne-t-il ?
Au moment de la compilation du projet, Next.js se chargera de télécharger toutes nos polices de caractères, et les mettra à côté des autres fichiers statiques de notre application. Ainsi, lorsqu'un utilisateur visitera notre application, il n'y aura plus de requêtes supplémentaires vers le serveur pour obtenir les polices de caractères. Ce qui accroîtra les performances de notre application.
Illustration
Revenons sur notre fichier layout.jsx
/app/layout.jsx
import Header from '@/components/Header';
import { Inter } from 'next/font/google';
import './globals.css';
const inter = Inter({ subsets: ['latin'] });
export const metadata = {
  title: 'Biblio-app',
  description: 'Demo Cours Programmation web avancé',
};
export default function RootLayout({ children }) {
  return (
    <html lang='en'>
      <body className={inter.className}>
        <Header />
        {children}
      </body>
    </html>
  );
}
La ligne 'import { Inter } from 'next/font/google';' permet d'importer la police Inter du module 'next/font/google'
La ligne 'const inter = Inter({ subsets: ['latin'] });' permet de spécifier que nous utliserons le style 'latin'
En fin, la ligne '<body className={inter.className}>' permet d'appliquer notre police à tout le contenu de notre page.

Image dans Next.js
Le composant Image
Comme les polices de caractères, les images doivent également être optimisées dans une application React avec Next.js. A cet effet, Next.js a prévu un composant spécial appelé 'Image'. Il s'agit d'une extension de la balise <img> connue habituellement comme balise d'insertion d'image dans une page web.
Vous avez sans doute dévinez qu'un lieu et place de la balise <img>, nous utiliserons le composant 'Image' pour insérer nos images. Cela pour plusieurs raisons:
Optimisation de la taille : Le composant 'Image' génère différentes versions d'une image pour s'adapter à divers affichages (taille d'écran, résolution)
Chargement paresseux (Lazy Loading) : Les images ne sont chargées que lorsqu'elles sont visibles dans le viewport, ce qui réduit le temps de chargement initial et économise la bande passante
Prise en charge des formats modernes : Next.js prend en charge des formats d'images modernes tels que AVIF et WebP, qui offrent de meilleures performances et des tailles de fichiers plus petites par rapport à des formats plus anciens comme JPEG et PNG.
Manipulation facile des attributs : Le composant 'Image' de Next.js offre des fonctionnalités avancées comme le redimensionnement, la recadrage, la gestion des ratios d'aspect, etc., permettant de contrôler précisément l'apparence et le comportement des images.
Illustration
Pour illustrer le fonctionnement du composant 'Image', nous allons ajouter un logo à notre application 'biblio-app'. Pour cela, il faut suivre les étapes suivantes:
Le logo : Télécharger le logo et le sauvegarder dans le dossier 'public' de 'biblio-app'.
Importer 'Image' : Au début du composant 'Header.jsx', Insérer le code qui va suivre pour importer le composant 'Image' de Next.
/components/Header.jsx
import Image from 'next/image';
Importer le logo : Toujours au début du composant 'Header.jsx', Insérer le code qui va suivre, pour importer le logo téléchargé.
/components/Header.jsx
import logo from '@/public/react.webp';
Usage de 'Image' : Juste après la ligne 'return <header ...>' du composant 'Header.jsx', Insérer le code qui va suivre.
/components/Header.jsx
<div className={styles.title}>
<Image
    src={logo}
    alt='Logo React'
    width={80}
/>
<h1>Titre du site web</h1>
</div>
Modifier CSS : Dans 'Header.module.css', ajouter le code CSS suivant :
/components/Header.module.css
.title {
    display: flex;
    align-items: center;
    gap: 1rem;
    color: #fff;
}
Il ne reste plus qu'à sauvegarder toutes les modifications pour voir le logo apparaitre.

Quelques trucs utiles
Maintenant que nous sommes assez armés pour créer la base de notre de notre application, il est important d'adopter de bonnes pratiques avant d'avancer. Ces bonnes pratiques nous permettrons d'avoir une application finale performante.
Les types d'images
Il est conseillé d'utiliser des formats d'images modernes tels que AVIF et WebP. en effet, ces formats offrent de meilleures performances et des tailles de fichiers plus petites par rapport à des formats plus anciens. A vous donc de choisir quel format utiliser.
Pour convertir vos images, vous pouvez utiliser des outils comme 'Squoosh', un outil de compression d'image de Google, qui permet de convertir des images entre différents formats, y compris AVIF et WebP, et de comparer leur qualité et leur taille.
Le contraste des couleurs
Il est important de savoir qu'un mauvais choix de couleurs de texte et d'arrière-plan, entraînera un contraste de mauvaise qualité et par conséquence, affectera les performances de votre application. Ainsi, vers la fin de ce cours, lorsque nous testerons les performances de l'application, vous serez contraint d'apporter de nombreuses modifications si les couleurs ont été mal choisies.
Pour éviter ce désagrément, vous pouvez vérifier le contraste de vos couleurs à partir du lien suivant:
CSS inutile
Débarrassez-vous progressivement de tout code CSS inutilisé. On a tendance à se dire qu'on fera le ménage à la fin, mais cela devient pénible lorsque le site devient grand.
Exercice d'application
En suivant la même logique, créez le pied de page ou footer de notre application biblio-app. Réorganiser aussi le Header, en créant un composant 'MenuNav' pour contenir le bloc 'nav' qui se trouve actuellment dans Header. Vous devez également créer un composant 'Accueil' qui contiendra tout le contenu actuel du fichier 'page.jsx', puis l'mporter dans ce dernier.

Code source
Important
Avant d'executer la commande 'npm run dev', bien vouloir exécuter la commande 'npm i'.

Travail à faire