Programmation

Introduction aux hooks

14 mai 2024

Table des matières:

  1. Les Hooks
  2. Qu’est-ce qu’un hook ?
  3. Quels intérêts peuvent avoir les hooks ?
  4. Le Hooks d’état (useState)
  5. Comment fonctionne le hook useState ?
  6. Le Hooks d’effet (useEffect)
  7. Intervenir sur la mise à jour d’un composant
  8. Intervenir sur le démontage d’un composant

Les Hooks

Avec React 16.8, une nouvelle fonctionnalité que l’on appelle les hooks sont arrivés. Ils coincident avec le fait d’utilier les functional components. Ils permettent notamment d’utiliser les fonctionnalités d’un class component mais pas uniquement.

Comme j’ai déjà pu vous faire la remarque, ce n’est pas parce que c’est une “nouveauté” dans React qu’il faut vous jeter dessus. Tout d’abord, les applications que vous avez développées sont 100% rétro-compatibles puisqu’un hook n’affecte pas les composants de classe. De plus, rien ne vous empêche de les introduires au fur et à mesure dans votre application sur de nouveaux composants : tant que le composant est un functional component.

Qu’est-ce qu’un hook ?

Un** hook** n’est ni plus, ni moins, qu’une fonction en JavaScript. Vous l’appelez comme une fonction avec la possibilité de lui passer un ou plusieurs paramètres et cette fonction va vous renvoyer un résultat. Cependant, un hook va suivre 2 règles fondamentales pour être utilisé.

Vous ne pouvez appeler un hook uniquement au plus haut niveau (la racine) de votre fonction. Vous ne pourrez donc pas appeler de hook dans une instruction algorithmique (boucle, structure conditionnel avec un if, etc… )

// Ce code va fonctionner
function Good() {
const [isOpen, setIsOpen] = useState(false);
 
return <>Go</>;
}
 
// Le hook ne peut pas fonctionner et vous aurez une erreur
function Fail() {
if (true) {
const [isOpen, setIsOpen] = useState(false);
}
 
return <>Go</>;
}

Appelez les hooks uniquement depuis des functional components. Vous ne devez pas appeler un hook dans une fonction JavaSript classique excepté si c’est un hook personnalisé.

Quels intérêts peuvent avoir les hooks ?

Les hooks n’ont pas fait leur introduction par hasard ; pourquoi les ajouter alors qu’on pouvait s’en sortir sans ? Si vous regardez quelques articles à ce sujet, il ya plusieurs raisons à cela.

Au fil du temps, il s’est avéré que les composants sont devenus de plus en plus complexe. Alors qu’ils devrait être simples comme on peut le voir depuis le début, chaque composant pouvait devenir une usine à gaz. Notamment lorsque vous deviez commencer à interagir avec le cycle de vie, vérifier les prevProps ou les nextProps. On doit implémenter des fonctionnalités dans un componentDidMount qu’il faut nettoyer dans une autre méthode componentWillUnmount, etc… Il était également difficile de découper ces composants en d’autres plus petits car les états pouvaient commencer à s’éparpiller.

Concernant les classes, on a pu voir aussi qu’elles peuvent être déroutantes car elles sont une barrière à l’apprentissage. Une classe est liée au fonctionnement complexe du this en JavaScript et cela vous rajoute une difficulté supplémentaire notamment à cause de l’objet en JavaScript qui est bien différent que la plupart des langages. On parle d’ailleurs de prototype exactement.

En d’autres termes, les hooks nous permettent d’utiliser davantage de fonctionnalités de React sans recourir aux classes. D’ailleurs, les composants React ont toujours été proches des fonctions et les Hooks tirent pleinement parti des fonctions, sans pour autant oublier l’esprit pratique de React.

Enfin, comme un hook est une fonction, en plus de l’intérêt de pouvoir accéder à l’état local d’un composant, il va vous permettre d’utiliser des logiques communes entre les composants. Telle une fonction qui factorise votre code, le hook va vous permettre de faire cette factorisation tout en vous permettant de réutiliser la logique à état entre les composants.

Le Hooks d’état (useState)

Le hook d’état fait parti des hooks de React que l’on va utiliser régulièrement puisqu’il permet de générer un état local (state) de son composant de fonction. Là où l’on a besoin de this.state dans un composant de classe, nous allons avoir besoin du hook d’état : useState pour un composant de fonction.

Dans un composant de class, nous gérons le state au niveau du this de la classe.

import React, { Component } from "react";
 
class ExampleComponent extends Component {
constructor(props) {
super(props);
this.state = {
count: 0,
openModal: false,
};
}
 
render() {
return <>Hello world</>;
}
}
 
export default ExampleComponent;

Dans cet exemple, nous avons donc un objet qui contient un état avec 2 clés. Si nous devions le représenter avec un composant de fonction, nous ferions comme ceci :

import { useState } from "react";
 
function ExampleComponent() {
const [count, setCount] = useState(0);
// Ce style d'écriture est de l'affectation par décomposition
const [openModal, setOpenModal] = useState(false);
 
return <>Hello world</>;
}

Comment fonctionne le hook useState ?

Comme on a pu le constater sur l’exemple ci-dessus,** useState est une fonction** qui prend un paramètre : la valeur de l’état que l’on souhaite définir. Pour le compteur, je souhaite le démarrer à** 0**.

const maValeurInitiale = 0;
const [monEtat, setMonEtat] = useState(maValeurInitiale);

En retour, la fonction useState nous donne un tableau qui contient 2 éléments :

  • Le premier (index 0) correspond à votre état
  • Le 2ème (index 1) est le “setter”. La fonction qui va vous permettre de modifier cet état. On lui connaît son équivalent avec this.setState pour les composants de classes

Le style d’écriture que l’on vient de voir concerne l’affectation par décomposition. Nous pourrions aussi avoir :

const countInformation = useState(0);
 
countInformation[0]; // L'état
countInformation[1]; // La fonction "setter"

Dès lors, vous pouvez maintenant utiliser votre état dans votre composant comme l’afficher et le modifier :

import { useState } from "react";
 
function Counter() {
const [count, setCount] = useState(0);
 
return (
<>
{/* J'affiche la valeur de "count" */}
<p>Mon état local "count" contient la valeur : {count}</p>
 
{/* En cliquant sur ce bouton, j'ajoute 1 à la valeur de mon compteur */}
<button onClick={() => setCount(count + 1)}>
Incrémenter la valeur de 1
</button>
 
{/* En cliquant sur ce bouton, je soustrais 1 à la valeur de mon compteur */}
<button onClick={() => setCount(count - 1)}>
Décrémenter la valeur de 1
</button>
</>
);
}

Vous aurez constatez que le mot-clé use revient régulièrement lorsque vous utilisez un hook. C’est une norme. On utilise (use) une information, on ne l’a crée pas.

Comme nous gérons un état local (state), la modification de celui-ci entraine évidemment le cycle de vie de mise à jour de React

Le Hooks d’effet (useEffect)

Le hook d’effet, comme pour le hook d’état, fait parti des hooks de React que l’on va utiliser régulièrement. Comme un composant de fonction n’a pas de méthode à disposition pour venir se positionner sur le cycle de vie d’un composant React, nous devons passer par ce hook d’effet : useEffect afin d’intervenir sur les évènements du cycle de vie du composant.

useEffect est une fonction qui accepte 2 paramètres :

  • Le 1er est une fonction de rappel (un callback) qui sera exécute pour l’effet que vous souhaitez “écouter”
  • Le 2ème est optionnel et permet de définir l’état (state ou props) que l’on souhaite observer
 
import { useEffect } from "react";
 
function ExampleComponent() {
useEffect(() => {
console.log("Je n'ai qu'un paramètre");
});
 
return <>Hello world</>;
}

Voici un exemple d’utilisation du useEffect avec uniquement un callback. Il aura pour effet de se déclencher sur le cycle de vie du montage et de la mise à jour. En somme, c’est l’équivalent de la fonction componentDidMount et componentDidUpdate. Sur un composant de classe nous aurions eu :

class ExampleComponent extends Component {
logMe() {
console.log("Je n'ai qu'un paramètre");
}
componentDidMount() {
this.logMe();
}
componentDidUpdate() {
this.logMe();
}
}

L’équivalent du componentDidMount

Afin d’intervenir uniquement durant le montage du composant, le componentDidMount, il vous faut ajouter le 2eme** paramètre** que peut accepter useEffect. Comme nous n’écoutons rien de particulier, nous allons lui fournir un tableau vide : []

import { useEffect } from "react";
 
function ExampleComponent() {
useEffect(() => {
console.log("Je suis comme un componentDidMount");
}, []);
return <>Hello world</>;
}

Intervenir sur la mise à jour d’un composant

Pour que vous puissiez effectuer des actions lors d’un changement d’état du composant, il va falloir que vous spécifiez l’état que vous souhaitez écouter dans le 2ème paramètre du useEffect. Ce paramètre est un tableau ce qui vous permet d’avoir un seul useEffect pour différents états. Vous pouvez également en distinguer plusieurs.

L’avantage par rapport à un composant de classe c’est que vous n’avez pas besoin de tester la prevProps et nextProps pour savoir sur quel élément vous souhaitez effectuer une action. Il vous suffit de passer la valeur au useEffect pour savoir ce que l’on est en train de traiter.

Par exemple, nous allons imaginer que nous souhaitons effectuer un appel API lorsque nous allons ouvrir une modal.

import { useEffect, useState } from "react";
 
function ExampleComponent() {
const [modalIsOpen, setModalIsOpen] = useState(false);
 
useEffect(() => {
// Ne rien faire si la modal est fermée
if (!modalIsOpen) {
return;
}
 
// Je fais un appel API uniquement lorsque l'état de modalIsOpen
// change à "true"
fetch("https://api.com");
}, [modalIsOpen]);
 
return (
<>
Hello world{" "}
<button onClick={() => setModalIsOpen(true)}>Open Modal</button>
</>
);
}

Attention, lorsque vous écoutez une valeur, l’exécution du useEffect intervient également à l’initialisation de la valeur comme sur le componentDidMount. Si vous ne souhaitez pas qu’il s’exécute, il faut penser à gérer la valeur par défaut / d’initialisation

Intervenir sur le démontage d’un composant

Chaque useEffect que vous déclarez vous donne accès à un callback permettant d’intervenir sur le démontage du composant. Il s’agit du retour de votre fonction dans le useEffect dans laquelle vous fournissez une fonction de rappelle.

useEffect(() => {
// Ce que vous voulez
return () => {
// Fonction de rappelle qui s'exécute lors du démontage
};
});

Cette fonction de rappelle va s’exécuter lors du démontage du composant. Vous aurez besoin de l’utiliser régulièrement si vous gérez des évènements spécifiques dans le contexte du JavaScript en général. Typiquement, si vous utilisez un setInterval dans un composant de fonction, il faudra bien penser à le couper!

function Counter() {
const [count, setCount] = useState(0);
 
useEffect(() => {
const countInterval = setInterval(() => {
setCount((count) => count + 1);
}, 1000);
 
return () => {
// Si vous ne le faites pas, vous générez une "fuite de mémoire"
clearInterval(countInterval);
};
}, []);
 
return <div style={{ fontWeight: "bold", fontSize: 90 }}>{count}</div>;
}

Partager cet article:

Daouda Thiam

Coach à Bakeli School of Technology

Bakeli est une école de formation professionnelle dans les nouvelles technologies créer par Volkeno. Elle a formé + de 6000 étudiants et professionnels aux métiers des nouvelles technologies et du digital.

Bakeli

Contacts

S'abonner à la Newsletter

Chargement en cours...

© Copyright 2024, Tous droits réservés.