logo oujood
🔍

Custom Hooks : Réutilisez Logique et État Entre Composants

OUJOOD.COM

Introduction

Les Custom Hooks sont des fonctions personnalisées qui permettent de réutiliser des fonctionnalités et de l'état entre plusieurs composants React. Ils offrent une solution élégante pour factoriser du code et éviter les duplications. Grâce aux Custom Hooks, vous pouvez encapsuler des logiques complexes dans des fonctions réutilisables, rendant ainsi votre code plus maintenable et scalable.

Dans ce chapitre, nous allons explorer :

  • Qu'est-ce qu'un Custom Hook ?
  • Comment créer un Custom Hook.
  • Des exemples pratiques pour illustrer leur utilisation.

1. Qu'est-ce qu'un Custom Hook ?

Un Custom Hook est simplement une fonction JavaScript dont le nom commence par use. Il peut appeler d'autres Hooks comme useState, useEffect, ou encore useReducer. Voici pourquoi ils sont utiles :

  • Réutilisation : Encapsulez des fonctionnalités communes dans un Custom Hook pour les réutiliser dans différents composants.
  • Maintenabilité : Concentrez toute la logique d'un aspect spécifique (par exemple, la gestion d'un compteur) dans un seul endroit.
  • Scalabilité : Simplifiez la gestion de l'état et des effets secondaires dans vos applications React.

2. Création d'un Custom Hook Simple

Voici un exemple simple où nous créons un Custom Hook appelé useCompteur pour gérer un compteur réutilisable :

📋 Copier le code

// useCompteur.js
import { useState, useEffect } from 'react';

function useCompteur(initialValue = 0) {
const [compte, setCompte] = useState(initialValue);

// Effet secondaire : Affiche le compteur dans la console à chaque changement
useEffect(() => {
console.log(`Le compteur a changé : ${compte}`);
}, [compte]);

return [compte, setCompte];
}

export default useCompteur;

Explication détaillée ligne par ligne :

  1. import { useState, useEffect } from 'react'; :
    • Nous importons les Hooks useState et useEffect depuis React.
    • useState est utilisé pour gérer l'état local du compteur (compte).
    • useEffect exécute un effet secondaire lorsqu'une certaine variable change.
  2. function useCompteur(initialValue = 0) { ... } :
    • Cette fonction définit notre Custom Hook appelé useCompteur.
    • Elle accepte un paramètre optionnel initialValue, qui spécifie la valeur initiale du compteur (par défaut : 0).
  3. const [compte, setCompte] = useState(initialValue); :
    • Cette ligne initialise l'état local du compteur avec la valeur initialValue.
    • setCompte est une fonction permettant de mettre à jour cet état.
  4. useEffect(() => { ... }, [compte]); :
    • Cet effet secondaire s'exécute à chaque fois que la valeur de compte change.
    • console.log(`Le compteur a changé : ${compte}`); : Affiche un message dans la console avec la nouvelle valeur du compteur.
  5. return [compte, setCompte]; :
    • Notre Custom Hook retourne un tableau contenant la valeur actuelle du compteur (compte) et la fonction pour le mettre à jour (setCompte).
  6. export default useCompteur; :
    • Cette ligne exporte notre Custom Hook pour qu'il soit utilisable dans d'autres fichiers ou composants.

3. Utilisation du Custom Hook dans un Composant

Maintenant que nous avons créé notre Custom Hook appelé useTheme, voyons comment l'utiliser dans un composant React pour gérer dynamiquement le thème de notre application. Cet exemple illustrera clairement comment intégrer un Custom Hook dans un composant fonctionnel.

📋 Copier le code

import React from 'react';
import useTheme from './useTheme'; // Importation du Custom Hook
import { createRoot } from 'react-dom/client';

function App() {
const [theme, toggleTheme] = useTheme(); // Utilisation du Custom Hook

// Styles conditionnels basés sur le thème actuel
const styles = {
container: {
	padding: '20px',
	textAlign: 'center',
	fontFamily: 'Arial, sans-serif',
	backgroundColor: theme === 'dark' ? '#333' : '#f9f9f9', // Arrière-plan selon le thème
	color: theme === 'dark' ? 'white' : 'black' // Couleur du texte selon le thème
},
button: {
	padding: '10px 20px',
	margin: '10px auto',
	display: 'block',
	border: 'none',
	borderRadius: '5px',
	cursor: 'pointer',
	backgroundColor: theme === 'dark' ? '#FFC107' : '#007BFF', // Couleur du bouton selon le thème
	color: 'white'
}
};

return (
<div style={styles.container}>
	<h1 style={{ color: theme === 'dark' ? '#FFC107' : '#007BFF' }}>Système de Thème avec Custom Hook</h1>
	<button 
		onClick={toggleTheme} 
		style={styles.button}
	>
		Changer de thème
	</button>
	<p>Thème actuel : {theme}</p>
</div>
);
}

const root = createRoot(document.getElementById('root')); // Création de la racine React (React 18+)
root.render(<App />); // Rendu du composant principal

Explication détaillée ligne par ligne :

  1. import React from 'react'; :
    • Nous importons React pour utiliser ses fonctionnalités, notamment JSX.
  2. import useTheme from './useTheme'; :
    • Cette ligne importe notre Custom Hook useTheme depuis le fichier useTheme.js.
    • Le Custom Hook encapsule toute la logique liée à la gestion du thème (initialisation, basculement, persistance).
  3. import { createRoot } from 'react-dom/client'; :
    • Cette ligne importe la méthode createRoot depuis react-dom/client, recommandée pour React 18 et versions ultérieures.
    • createRoot remplace ReactDOM.render() pour un rendu plus moderne et aligné avec les futures évolutions de React.
  4. function App() { ... } :
    • Ce composant fonctionnel est le point d'entrée de notre application.
    • Il utilise notre Custom Hook useTheme pour gérer dynamiquement le thème global.
  5. const [theme, toggleTheme] = useTheme(); :
    • Ici, nous utilisons notre Custom Hook useTheme pour initialiser deux valeurs : theme (le thème actuel) et toggleTheme (la fonction pour basculer entre les thèmes).
    • theme représente soit 'light' (mode clair), soit 'dark' (mode sombre).
    • toggleTheme est une fonction qui alterne entre ces deux modes.
  6. const styles = { ... }; :
    • Cette variable définit des styles CSS sous forme d'objets JavaScript pour personnaliser l'apparence de notre composant.
    • container : Définit les styles du conteneur principal.
    • backgroundColor : Change dynamiquement l'arrière-plan selon la valeur de theme. Si theme est 'dark', l'arrière-plan devient noir (#333); sinon, il reste blanc (#f9f9f9).
    • color : Change dynamiquement la couleur du texte selon la valeur de theme. Si theme est 'dark', le texte devient blanc; sinon, il reste noir.
    • button : Définit les styles du bouton "Changer de thème".
    • backgroundColor : Change la couleur du fond du bouton selon la valeur de theme. En mode sombre, le bouton est orange (#FFC107); en mode clair, il est bleu (#007BFF).
    • color : Le texte du bouton reste toujours blanc (white) pour contraster avec les arrière-plans colorés.
  7. <div style={styles.container}> :
    • Cet élément <div> est stylisé avec les propriétés définies dans styles.container.
    • Son apparence change dynamiquement en fonction de la valeur actuelle de theme.
  8. <h1 style={{ color: theme === 'dark' ? '#FFC107' : '#007BFF' }}>...</h1> :
    • Cet élément <h1> affiche un titre centré ("Système de Thème avec Custom Hook").
    • La couleur du texte change dynamiquement selon la valeur de theme. En mode sombre, elle est orange (#FFC107); en mode clair, elle est bleue (#007BFF).
  9. <button onClick={toggleTheme} style={styles.button}>...</button> :
    • Ce bouton permet à l'utilisateur de basculer entre les modes clair et sombre.
    • onClick={toggleTheme} : Lorsque le bouton est cliqué, il appelle la fonction toggleTheme renvoyée par notre Custom Hook.
    • style={styles.button} : Applique les styles définis dans styles.button, y compris la couleur de fond et du texte selon le thème actuel.
  10. >p<Thème actuel : {theme}>/p< :
    • Cet élément <p> affiche dynamiquement le thème actuel (theme) : soit 'light', soit 'dark'.
    • Grâce à cette indication visuelle, l'utilisateur peut voir immédiatement quel thème est activé.
  11. const root = createRoot(document.getElementById('root')); :
    • Cette ligne crée une instance de racine React appelée root.
    • document.getElementById('root') spécifie l'élément HTML où notre application sera insérée.
  12. root.render(<App />); :
    • Cette ligne rend notre composant principal App dans l'élément HTML ayant l'id root.
    • En utilisant createRoot, nous garantissons une compatibilité avec React 18 et versions ultérieures.

Pourquoi Utiliser un Custom Hook dans ce Cas ?

En encapsulant toute la logique de gestion du thème dans un Custom Hook (useTheme), nous obtenons plusieurs avantages significatifs :

  • Réutilisation : La gestion du thème peut être partagée entre plusieurs composants sans duplication de code.
  • Maintenabilité : Toute la logique liée au thème est centralisée dans un seul fichier (useTheme.js), facilitant ainsi les mises à jour ou modifications futures.
  • Scalabilité : Si nous souhaitons ajouter des fonctionnalités supplémentaires (par exemple, plusieurs thèmes ou animations), cela peut être fait facilement dans le Custom Hook sans affecter les composants qui l'utilisent.
  • Optimisation des Performances : En évitant de recalculer inutilement des états ou effets secondaires dans chaque composant, nous réduisons la charge de travail de React.

Comment Fonctionne cet Exemple en Détail ?

Voici une explication pas à pas de ce qui se passe lorsqu'un utilisateur interagit avec notre application :

  1. Initialisation du Thème : Lorsque le composant App est monté, il appelle notre Custom Hook useTheme pour initialiser le thème actuel (theme) et obtenir la fonction toggleTheme.
  2. Affichage Dynamique : Les styles du composant (styles.container et styles.button) sont ajustés en fonction de la valeur actuelle de theme. Par exemple, si theme est 'dark', l'arrière-plan devient noir et le texte blanc.
  3. Basculement du Thème : Lorsque l'utilisateur clique sur le bouton "Changer de thème", la fonction toggleTheme est exécutée. Cela met à jour l'état theme via setTheme, tout en sauvegardant la nouvelle valeur dans le localStorage pour une persistance entre les sessions.
  4. Re-render Automatique : Après que theme a été mis à jour, React détecte le changement d'état et re-rend le composant App avec les nouveaux styles adaptés au thème sélectionné.

4. Exemple Avancé : Gestion d'un Thème Global avec un Custom Hook

Imaginons que vous souhaitiez créer un système de thème global pour votre application React (par exemple, mode clair ou mode sombre). Au lieu de dupliquer cette logique dans plusieurs composants, nous pouvons encapsuler toute la gestion du thème dans un Custom Hook réutilisable.

📋 Copier le code

// useTheme.js
import { useState, useEffect } from 'react';

function useTheme(initialTheme = 'light') {
const [theme, setTheme] = useState(initialTheme);

// Enregistre le thème dans le localStorage pour une persistance entre les sessions
useEffect(() => {
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
	setTheme(savedTheme); // Charge le thème sauvegardé au montage
}
}, []);

// Met à jour le thème et le stocke dans le localStorage
const toggleTheme = () => {
const newTheme = theme === 'light' ? 'dark' : 'light';
setTheme(newTheme);
localStorage.setItem('theme', newTheme); // Persistance du thème
};

return [theme, toggleTheme];
}

export default useTheme;

// App.js
import React from 'react';
import useTheme from './useTheme';
import { createRoot } from 'react-dom/client';

function App() {
const [theme, toggleTheme] = useTheme(); // Utilise le Custom Hook

const styles = {
container: { padding: '20px', textAlign: 'center', fontFamily: 'Arial, sans-serif' },
body: { backgroundColor: theme === 'dark' ? '#333' : '#f9f9f9', color: theme === 'dark' ? 'white' : 'black' }
};

return (
<div style={styles.container}>
	<h1 style={{ color: theme === 'dark' ? '#FFC107' : '#007BFF' }}>Système de Thème avec Custom Hook</h1>
	<button onClick={toggleTheme} style={{ padding: '10px 20px', margin: '10px auto', display: 'block' }}>
		Changer de thème
	</button>
	<p>Thème actuel : {theme}</p>
</div>
);
}

const root = createRoot(document.getElementById('root'));
root.render(<App />);

Explication détaillée ligne par ligne :

  1. function useTheme(initialTheme = 'light') { ... } :
    • Cette fonction définit notre Custom Hook appelé useTheme.
    • Elle accepte un paramètre optionnel initialTheme, qui spécifie le thème initial (par défaut : 'light').
  2. const [theme, setTheme] = useState(initialTheme); :
    • Cette ligne initialise un état local appelé theme avec la valeur initiale passée (initialTheme).
    • setTheme est une fonction permettant de mettre à jour cet état.
  3. useEffect(() => { ... }, []); :
    • Cet effet secondaire s'exécute une seule fois au montage du composant.
    • Il vérifie si un thème a été sauvegardé précédemment dans le localStorage.
    • Si un thème est trouvé, il met à jour l'état theme avec cette valeur.
  4. localStorage.getItem('theme'); :
    • Cette méthode récupère la valeur du thème sauvegardée dans le localStorage.
    • Le localStorage est un mécanisme natif du navigateur qui permet de stocker des données persistantes.
  5. const toggleTheme = () => { ... }; :
    • Cette fonction permet de basculer entre le mode clair ('light') et le mode sombre ('dark').
    • Elle met également à jour le localStorage pour garantir que le thème est conservé même après un rechargement de la page.
  6. return [theme, toggleTheme]; :
    • Notre Custom Hook retourne un tableau contenant la valeur actuelle du thème (theme) et la fonction pour le basculer (toggleTheme).
  7. import useTheme from './useTheme'; :
    • Dans notre composant principal (App.js), nous importons notre Custom Hook useTheme.
  8. const [theme, toggleTheme] = useTheme(); :
    • Nous utilisons notre Custom Hook pour initialiser l'état du thème (theme) et obtenir la fonction pour le basculer (toggleTheme).
  9. const styles = { ... }; :
    • Cette variable définit des styles conditionnels basés sur la valeur actuelle du thème.
    • backgroundColor change dynamiquement selon que le thème est 'light' ou 'dark'.
    • color ajuste également la couleur du texte pour garantir un bon contraste.
  10. <button onClick={toggleTheme}>Changer de thème</button> :
    • Ce bouton appelle la fonction toggleTheme lorsqu'il est cliqué.
    • Cela bascule le thème entre 'light' et 'dark', tout en mettant à jour le localStorage.

5. Avantages des Custom Hooks

Les Custom Hooks offrent plusieurs avantages significatifs pour structurer et optimiser votre code React :

  • Réutilisation de Logique : Encapsulez des fonctionnalités communes dans un Custom Hook pour les réutiliser facilement dans différents composants.
  • Maintenabilité : Concentrez toute la logique liée à un aspect spécifique (par exemple, la gestion d'un thème) dans un seul endroit, rendant votre code plus facile à maintenir.
  • Scalabilité : Les Custom Hooks simplifient la gestion de l'état et des effets secondaires complexes, ce qui est essentiel pour les applications React grandissantes.
  • Optimisation des Performances : En combinant des Hooks comme useState et useEffect, vous pouvez éviter des duplications inutiles et améliorer les performances globales de votre application.

6. Meilleures Pratiques pour Créer des Custom Hooks

Pour créer des Custom Hooks efficaces et maintenables, voici quelques conseils pratiques :

  • Nommez-les Correctement : Commencez toujours le nom de votre Custom Hook par use (ex. useCompteur, useTheme). Cela indique clairement qu'il s'agit d'un Hook personnalisé.
  • Gardez-les Réutilisables : Conçus vos Custom Hooks pour être utilisés dans différents contextes, sans dépendance excessive à un composant particulier.
  • Testez-les Indépendamment : Avant de les intégrer dans vos composants principaux, testez vos Custom Hooks individuellement pour vous assurer qu'ils fonctionnent correctement.
  • Documentez-les Bien : Ajoutez des commentaires ou une documentation explicite pour clarifier leur rôle et leur usage.

7. Cas d'Utilisation Courants pour les Custom Hooks

Les Custom Hooks sont particulièrement utiles dans les scénarios suivants :

  • Gestion d'États Complexes : Par exemple, la gestion d'un panier d'achat ou d'une liste de tâches.
  • Interactions avec le DOM : Encapsulez des interactions DOM récurrentes dans un Custom Hook pour les réutiliser facilement.
  • Appels API : Créez un Custom Hook pour gérer les appels API, y compris le chargement et les erreurs.
  • Gestion de Contextes : Comme illustré dans l'exemple précédent, les Custom Hooks peuvent simplifier la gestion de contextes comme les thèmes ou les informations utilisateur.

Conclusion

Vous avez maintenant appris à créer et utiliser des Custom Hooks en React. Ces Hooks personnalisés permettent de factoriser et de réutiliser des fonctionnalités complexes, rendant ainsi votre code plus maintenable, scalable et performant. Grâce aux Custom Hooks, vous pouvez encapsuler des logiques spécifiques (comme la gestion d'un compteur ou d'un thème) et les partager facilement entre plusieurs composants.

Prochain chapitre : Formulaires Avancés