3
Module 3
État, événement et Affichage
A la fin de ce troisième module, l'étudiant devra être capable d'afficher des données sur l'interface graphique, dépendant d'un état précis et suite à un événement.

Notion de hook dans React
Les hooks dans React sont des fonctions permettant au développeurs de bénéficier de nombreuses fonctionnalités sans avoir à écrire de classes. Les noms de ces fonctions (hooks) commencent généralement par 'use'. Parmi elles, on peut citer :
useState : Il permet de gérer l'état local dans un composant fonctionnel. Il renvoie une paire de valeurs : la valeur actuelle de l'état et une fonction pour le mettre à jour.
useEffect : Il permet de gérer les effets secondaires, tels que les appels réseau, les abonnements, ou la modification du DOM, dans un composant fonctionne
useContext : Il permet d'accéder à un contexte React, facilitant le partage de données entre composants sans avoir à passer des props explicitement à chaque niveau de la hiérarchie

Le hook d'état ou useState
Comme nous l'avais dit précédemment, le hook d'état permet de gérer l'état local dans un composant fonctionnel. Il renvoie une paire de valeurs : la valeur actuelle de l'état et une fonction pour le mettre à jour. Pour l'illustrer, nous allons reprendre notre application biblio-app dans son état final dans le module2.
Travail à faire
Nous allons dans un premier temps créer 3 nouveaux composants pour les contenus des menus 'Documents', 'Contact' et 'Connexion' de notre application. Par le suite, nous allons lier chaque bouton de la barre de navigation à son composant correspondant. Pour y parvenir, nous suivrons les étapes suivantes:
Créer les composants : Vous devez créer dans le dossier 'components', 3 composants nommées 'Documents', 'Contact' et 'Connexion'. Chaque composant devra contenir juste son 'nom'. Exemple: le composant 'Documents' doit simplement afficher le mot 'Document'.
Importer les nouveaux composants dans 'layout.jsx' : Cela se fait avec le code suivant au debut du fichier
/app/layout.jsx
'use client'
import Documents from '@/components/Documents';
import Connexion from '@/components/Connexion';
import Contact from '@/components/Contact';
Importer le hook 'useState' : Cela se fait avec le code suivant au debut du fichier
/app/layout.jsx
import { useState } from 'react';
Créer la paire de valeurs : Cela consite à créer la paire qui recevra la valeur la page courante et la fonction pour la mettre à jour. Cela se fait grâce au code suivant juste après la ligne 'export default function RootLayout({ children })'
/app/layout.jsx
 const [page, setPage] = useState('accueil');
Affichage conditionnel (nous y reviendrons) : Dans 'layout.jsx', remplacer '{children}' par le code suivant :
/app/layout.jsx
{page === 'accueil' ?
<Accueil />
: page === 'documents' ?
  <Documents />
  : page === 'contact' ?
    <Contact />
    : page === 'connexion' ?
      <Connexion />
      : <div>404 - Not Found</div>
}
Explication
A ce stade, nous avons 4 composants pouvant être affichés, en fonction du contenu de la variable 'page' qui est produit par notre hook 'useState'. Etant donné que le 'useState' à été initialisé avec 'accueil', le composant 'Accueil' sera donc affiché par défaut. Si nous remplaçons la valeur initiale du 'useState par 'documents', c'est plutôt le composant 'Documents' qui sera affiché.
Etat final du fichier 'layout.jsx'
/app/layout.jsx
'use client'
import Documents from '@/components/Documents';
import Connexion from '@/components/Connexion';
import Contact from '@/components/Contact';
import { useState } from 'react';
import Accueil from '@/components/Accueil';
import Header from '@/components/Header';
import { Inter } from 'next/font/google';
import Footer from '@/components/Footer';
import './globals.css';
import styles from './layout.module.css';
const inter = Inter({ subsets: ['latin'] });
export default function RootLayout({ children }) {
  const [page, setPage] = useState('accueil');
  return (
    <html lang='en'>
      <body className={inter.className + ' ' + styles.body}>
        <Header />
        {/* {children} */}
        <main className={styles.main}>
          {page === 'accueil' ?
            <Accueil />
            : page === 'documents' ?
              <Documents />
              : page === 'contact' ?
                <Contact />
                : page === 'connexion' ?
                  <Connexion />
                  : <div>404 - Not Found</div>
          }
        </main>
        <Footer />
      </body>
    </html>
  );
}
Transferer la fonction 'setPage' au composant '<Header>' : Dans 'layout.jsx', remplacer <Header> par le code suivant :
/app/layout.jsx
<Header setPage={setPage}/>
Passer la fonction 'setPage' comme props au composant '<Header>' : Dans 'Header.jsx', remplacer la ligne 'export default function Header()' par le code suivant :
/components/Header.jsx
export default function Header({setPage})
Transferer la fonction 'setPage' au composant '<MenuNav>' : Dans 'Header.jsx', remplacer <MenuNav />par le code suivant :
/components/Header.jsx
<MenuNav setPage={setPage} />
Remplacer le code du composant 'MenuNav' par le code suivant :
/components/MenuNav.jsx
import styles from './MenuNav.module.css';
export default function MenuNav({ setPage }) {
    return <nav className={styles.nav}>
        <ul>
            <li><a href='#' onClick={() => setPage('accueil')}>Accueil</a></li>
            <li><a href='#' onClick={() => setPage('documents')}>Documents</a></li>
            <li><a href='#' onClick={() => setPage('contact')}>Contact</a></li>
            <li><a href='#' onClick={() => setPage('connexion')}>Connexion</a></li>
        </ul>
    </nav>;
}
Remarque
A ce stade, l'état de notre variable 'page' change lorsqu'on clique sur un bouton de la barre de navigation. Ce qui permet ainsi de changer le composant courant. Cela grâce au 'useState' que nous avons importé. De nombreux autres exmples utiles seront présentés tout au long de notre cours.
Exercie d'application
Créer un nouveau composant nommé 'Compteur' qui réalise les actions suivantes : Créer un compteur qui affihce initialement 0 et un bouton qui permet d'incrémeter le compteur lorsqu'on clique dessus. Vous devez utiliser l'événement 'onClick' comme précédemment dans le composant 'MenuNav'. importer ensuite ce comopsant dans votre comoposant 'Accueil'.

Gestion des événements
Pour illustrer la gestion des événements dans Réact, dans notre composant 'Documents', nous allons créer un bouton permettant d'ajouter un nouveau livre lorsqu'on clique dessus. Pour cela, il faut remplacer les contenus des fichiers 'Docouments.jsx' et 'Docouments.module.css', par les codes qui vont suivre.
/components/Documents.jsx
import { useState } from 'react';
import styles from './Documents.module.css';
export default function Livres() {
    const [livres, setLivres] = useState([]);
    const [newLivre, setNewLivre] = useState('');
    const addLivre = () => {
        if (newLivre !== '') {
            setLivres([...livres, newLivre]);
            setNewLivre('');
        }
    };
    return (
        <div className={styles.container}>
            <h1>Gestion des livres</h1>
            <div>
                <input
                    type='text'
                    placeholder='Ajouter un livre'
                    value={newLivre}
                    onChange={(e) => setNewLivre(e.target.value)}
                />
                <button onClick={addLivre}>Ajouter</button>
            </div>
            <h2>Liste des livres</h2>
            <ul>
                {livres.map((livre, index) => (
                    <li key={index}>{livre}</li>
                ))}
            </ul>
        </div>
    );
}
/components/Documents.module.css
.container{
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-top: 2rem;
}
.container h1{
    margin-bottom: 1rem;
}
.container h2{
    margin-top: 1rem;
}
Explications
Dans cet exemple, nous avons l'événement 'onChange' qui gère l'affichage du nom du livre dans la zone de saisie, nous avons aussi l'événement 'onClick' qui permet d'ajouter le livre dans la liste des livres. De nombreux autres événements peuvent être utilisés et nous auront beaucoup d'autres examples dans le suite du cours.

Affichage conditionnel
Dans, nous disposons de 3 techniques pour faire de l'affichage conditionnelle des données. Pour illustrer cela, nous allons reprendre le code de notre layout de base.
L'opérateur ternaire : Le 'main' de notre layout de base a été rédigé en utilsant cet opérateur
/app/layout.jsx
<main className={styles.main}>
{page === 'accueil' ?
  <Accueil />
  : page === 'documents' ?
    <Documents />
    : page === 'contact' ?
      <Contact />
      : page === 'connexion' ?
        <Connexion />
        : <div>404 - Not Found</div>
}
</main>
Le ET logique (&&) : On peut réécrire le 'main' de notre layout avec l'opérateur 'ET logique'
/app/layout.jsx
<main className={styles.main}>
{page === 'accueil' && <Accueil />}
{page === 'documents' && <Documents />}
{page === 'contact' && <Contact />}
{page === 'connexion' && <Connexion />}
</main>
Le si ordinaire (if ... else ...) : On peut réécrire le 'main' de notre layout avec le si ordinaire
/app/layout.jsx
export default function RootLayout({ children }) {
const [page, setPage] = useState('accueil');
let content;
if (page === 'accueil') {
content = <Accueil />;
}
else if (page === 'documents') {
content = <Documents />;
}
else if (page === 'contact') {
content = <Contact />;
}
else if (page === 'connexion') {
content = <Connexion />;
}
else {
content = '<div>404 - Not Found</div>';
}
return (
    <html lang='en'>
    <body className={inter.className + ' ' + styles.body}>
        <Header setPage={setPage} />
        <main className={styles.main}>
        {content}
        </main>
        <Footer />
    </body>
    </html>
);
}

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

Travail à faire