Formation > Blog > Langage > Top 10 des Hooks React personnalisés les plus utiles

Ces puissants outils vous permettront de réutiliser la logique d’état sans modifier la hiérarchie de vos composants.

Cet article, vous fera explorer l’univers fascinant des Hooks personnalisés et comment ils peuvent enrichir vos développements React.

Avant de se lancer

L’équipe Ambient IT

Table des matières

  1. useToggle
  2. useTimeout
  3. useDebounce
  4. useUpdateEffect
  5. useArray
  6. usePrevious
  7. useStateWithHistory
  8. useStorage
  9. useAsync
  10. useFetch

Introduction

Qu’est-ce qu’un Hook ?

Un Hook est une fonction particulière qui vous permet d’« accrocher » dans les fonctionnalités de React, telles que la gestion de l’état ou le cycle de vie, depuis un composant fonctionnel. Avant l’introduction des Hooks, dans la version 16.8, ces fonctionnalités étaient exclusivement disponibles dans les composants de classe.

Comment créer un Hook personnalisé ?

La création d’un Hook personnalisé se fait par la définition d’une fonction qui commence par use, suivi du nom de votre Hook. À l’intérieur, vous pouvez utiliser d’autres Hooks React pour construire votre propre logique réutilisable.

Pourquoi les Hooks sont-ils révolutionnaires ?

Les Hooks offrent une alternative plus simple et plus puissante aux composants de classe. Ils permettent d’écrire des composants plus lisibles et maintenables tout en facilitant le partage et la réutilisation de la logique entre les composants sans avoir à recourir à des patterns complexes comme les render props ou les higher-order components.

1. useToggle

Le Hook useToggle est idéal pour gérer l’état de bascule entre deux valeurs, généralement true et false. C’est un excellent candidat pour gérer l’affichage d’une boîte de dialogue, un menu déroulant ou tout autre composant nécessitant un état on/off.

Quand utiliser useToggle ?

Utilisez useToggle quand vous avez besoin d’un mécanisme simple pour changer l’état d’un composant entre deux états. Cela simplifie votre code et le rend plus expressif et facile à comprendre.

import { useState } from "react"

export default function useToggle(defaultValue) {
  const [value, setValue] = useState(defaultValue)

  function toggleValue(value) {
    setValue(currentValue =>
      typeof value === "boolean" ? value : !currentValue
    )
  }

  return [value, toggleValue]
}

2. useTimeout

Avec useTimeout, vous pouvez retarder l’exécution d’une fonction de rappel. Ce Hook est pratique pour des cas comme la gestion des notifications qui doivent disparaître après un certain temps ou pour retarder une opération jusqu’à ce que le délai soit écoulé.

Comment utiliser useTimeout ?

Vous passez la fonction de rappel et le délai à useTimeout, et il s’occupera d’exécuter votre fonction après le temps défini. Vous obtenez également des fonctions pour annuler ou redémarrer le délai, offrant ainsi un contrôle précis sur l’exécution du délai.

import { useCallback, useEffect, useRef } from "react"

export default function useTimeout(callback, delay) {
  const callbackRef = useRef(callback)
  const timeoutRef = useRef()

  useEffect(() => {
    callbackRef.current = callback
  }, [callback])

  const set = useCallback(() => {
    timeoutRef.current = setTimeout(() => callbackRef.current(), delay)
  }, [delay])

  const clear = useCallback(() => {
    timeoutRef.current && clearTimeout(timeoutRef.current)
  }, [])

  useEffect(() => {
    set()
    return clear
  }, [delay, set, clear])

  const reset = useCallback(() => {
    clear()
    set()
  }, [clear, set])

  return { reset, clear }
}

3. useDebounce

Ce Hook est essentiel lorsque vous travaillez avec des entrées utilisateur sur des opérations coûteuses comme la recherche en temps réel. Il permet de limiter le nombre d’appels de fonctions en ajoutant un délai avant l’exécution de la fonction.

Pourquoi utiliser useDebounce pour les entrées utilisateur ?

L’utilisation de useDebounce pour les entrées utilisateur réduit le stress sur les ressources en évitant les calculs et requêtes inutiles, ce qui rend l’expérience utilisateur plus fluide et réactive.

import { useEffect } from "react"
import useTimeout from "../2-useTimeout/useTimeout"

export default function useDebounce(callback, delay, dependencies) {
  const { reset, clear } = useTimeout(callback, delay)
  useEffect(reset, [...dependencies, reset])
  useEffect(clear, [])
}

4. useUpdateEffect

Parfois, vous voulez exécuter un effet uniquement en réponse à des changements d’état, et non lors du montage initial du composant. useUpdateEffect est la solution pour ces cas.

Quelle est la différence entre useEffect et useUpdateEffect ?

useEffect s’exécute après le premier rendu et après chaque mise à jour du composant. En revanche, useUpdateEffect, ignore le premier rendu et s’exécute seulement après les mises à jour, grâce à un suivi de la première exécution.

Dans quelles situations préférer useUpdateEffect ?

useUpdateEffect est idéal lorsque des actions spécifiques doivent être effectuées en réponse aux changements d’état, tels que les requêtes API qui ne doivent pas être déclenchées lors du premier rendu.

import { useEffect, useRef } from "react"

export default function useUpdateEffect(callback, dependencies) {
  const firstRenderRef = useRef(true)

  useEffect(() => {
    if (firstRenderRef.current) {
      firstRenderRef.current = false
      return
    }
    return callback()
  }, dependencies)
}

5. useArray

Gérer les états de tableau dans React peut être complexe. useArray simplifie cette tâche en offrant des fonctions pour ajouter, supprimer, filtrer ou mettre à jour des éléments du tableau.

Quelles opérations offre useArray pour la gestion des listes ?

Avec useArray, vous disposez de méthodes pour manipuler des listes d’état de manière déclarative et immuable, sans avoir à gérer la complexité de la mise à jour des états de tableau en React.

Pourquoi useArray est-il idéal pour les listes dynamiques ?

Il permet de gérer facilement les listes d’éléments dynamiques, comme les to-do lists ou les galeries d’images, dans lesquels, les éléments sont fréquemment ajoutés ou supprimés par les utilisateurs.

import { useState } from "react"

export default function useArray(defaultValue) {
  const [array, setArray] = useState(defaultValue)

  function push(element) {
    setArray(a => [...a, element])
  }

  function filter(callback) {
    setArray(a => a.filter(callback))
  }

  function update(index, newElement) {
    setArray(a => [
      ...a.slice(0, index),
      newElement,
      ...a.slice(index + 1, a.length),
    ])
  }

  function remove(index) {
    setArray(a => [...a.slice(0, index), ...a.slice(index + 1, a.length)])
  }

  function clear() {
    setArray([])
  }

  return { array, set: setArray, push, filter, update, remove, clear }
}

6. usePrevious

C’est un Hook simple, mais puissant qui vous permet de capturer et de comparer les valeurs précédentes d’un état, ce qui est particulièrement utile pour les transitions ou les animations.

Comment usePrevious fonctionne-t-il ?

Ce Hook utilise useRef pour conserver la valeur précédente d’un état entre les rendus, sans déclencher une mise à jour du composant lui-même.

Quels sont les exemples d’utilisation de usePrevious?

Vous pouvez utiliser usePrevious pour détecter les changements d’état, pour implémenter des comportements personnalisés lors des mises à jour ou pour gérer les transitions d’état de manière plus sophistiquée.

import { useRef } from "react"

export default function usePrevious(value) {
  const currentRef = useRef(value)
  const previousRef = useRef()

  if (currentRef.current !== value) {
    previousRef.current = currentRef.current
    currentRef.current = value
  }

  return previousRef.current
}

7. useStateWithHistory

Si vous avez besoin d’un suivi de l’historique des valeurs d’un étatuseStateWithHistory est le Hook qu’il vous faut. Il vous permet de naviguer entre les états passés et actuels, similaire à la fonctionnalité « undo/redo ».

Comment naviguer entre les états passés avec useStateWithHistory ?

Ce Hook vous fournit des fonctions pour revenir à l’état précédent, avancer à l’état suivant ou aller directement à un état spécifique de l’historique.

Quand faut-il envisager d’utiliser useStateWithHistory ?

Il est particulièrement utile dans les éditeurs de texte, les jeux ou toute application nécessitant une fonctionnalité « annuler » ou « rétablir ».

import { useCallback, useRef, useState } from "react"

export default function useStateWithHistory(
  defaultValue,
  { capacity = 10 } = {}
) {
  const [value, setValue] = useState(defaultValue)
  const historyRef = useRef([value])
  const pointerRef = useRef(0)

  const set = useCallback(
    v => {
      const resolvedValue = typeof v === "function" ? v(value) : v
      if (historyRef.current[pointerRef.current] !== resolvedValue) {
        if (pointerRef.current < historyRef.current.length - 1) {
          historyRef.current.splice(pointerRef.current + 1)
        }
        historyRef.current.push(resolvedValue)

        while (historyRef.current.length > capacity) {
          historyRef.current.shift()
        }
        pointerRef.current = historyRef.current.length - 1
      }
      setValue(resolvedValue)
    },
    [capacity, value]
  )

  const back = useCallback(() => {
    if (pointerRef.current <= 0) return
    pointerRef.current--
    setValue(historyRef.current[pointerRef.current])
  }, [])

  const forward = useCallback(() => {
    if (pointerRef.current >= historyRef.current.length - 1) return
    pointerRef.current++
    setValue(historyRef.current[pointerRef.current])
  }, [])

  const go = useCallback(index => {
    if (index < 0 || index > historyRef.current.length - 1) return
    pointerRef.current = index
    setValue(historyRef.current[pointerRef.current])
  }, [])

  return [
    value,
    set,
    {
      history: historyRef.current,
      pointer: pointerRef.current,
      back,
      forward,
      go,
    },
  ]
}

8. useStorage

Le Web Storage, incluant LocalStorage et SessionStorage, est une façon courante de persister des données côté client. useStorage synchronise l’état d’un composant avec ces mécanismes de stockage.

Quelles sont les différences entre useLocalStorage et useSessionStorage ?

useLocalStorage persiste les données même après la fermeture du navigateur, tandis que useSessionStorage les conserve uniquement pour la durée de la session actuelle. useStorage vous permet de choisir entre les deux en fonction de vos besoins.

Comment et quand utiliser useStorage dans la pratique ?

useStorage est idéal pour sauvegarder les préférences utilisateur, l’état des formulaires ou toutes les autres données doivent être conservées entre les sessions de navigation.

import { useCallback, useState, useEffect } from "react"

export function useLocalStorage(key, defaultValue) {
  return useStorage(key, defaultValue, window.localStorage)
}

export function useSessionStorage(key, defaultValue) {
  return useStorage(key, defaultValue, window.sessionStorage)
}

function useStorage(key, defaultValue, storageObject) {
  const [value, setValue] = useState(() => {
    const jsonValue = storageObject.getItem(key)
    if (jsonValue != null) return JSON.parse(jsonValue)

    if (typeof defaultValue === "function") {
      return defaultValue()
    } else {
      return defaultValue
    }
  })

  useEffect(() => {
    if (value === undefined) return storageObject.removeItem(key)
    storageObject.setItem(key, JSON.stringify(value))
  }, [key, value, storageObject])

  const remove = useCallback(() => {
    setValue(undefined)
  }, [])

  return [value, setValue, remove]
}

9. useAsync

gérer les opérations asynchrones

Les opérations asynchrones, telles que les requêtes API, sont omniprésentes dans les applications web modernes. useAsync simplifie la gestion de l’état de chargement, des erreurs et des valeurs résultantes de ces opérations.

Comment useAsync simplifie-t-il le cycle de vie d’une requête asynchrone?

En encapsulant la logique de chargement, de gestion des erreurs et de mise à jour de l’état dans un Hook, useAsync rend le code de votre composant plus clair et plus facile à maintenir.

import { useCallback, useEffect, useState } from "react"

export default function useAsync(callback, dependencies = []) {
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState()
  const [value, setValue] = useState()

  const callbackMemoized = useCallback(() => {
    setLoading(true)
    setError(undefined)
    setValue(undefined)
    callback()
      .then(setValue)
      .catch(setError)
      .finally(() => setLoading(false))
  }, dependencies)

  useEffect(() => {
    callbackMemoized()
  }, [callbackMemoized])

  return { loading, error, value }
}

10. useFetch

Comment simplifier les requêtes fetch ?

Ce Hook est construit sur useAsync pour simplifier les requêtes réseau en utilisant l’API fetch native de JavaScript.

Pourquoi choisir useFetch pour vos appels réseau en React ?

useFetch est une solution pour effectuer des requêtes réseau, vous libérant ainsi des soucis liés à la gestion des requêtes HTTP et vous permettant de vous concentrer sur la présentation des données.

import useAsync from "../9-useAsync/useAsync"

const DEFAULT_OPTIONS = {
  headers: { "Content-Type": "application/json" },
}

export default function useFetch(url, options = {}, dependencies = []) {
  return useAsync(() => {
    return fetch(url, { ...DEFAULT_OPTIONS, ...options }).then(res => {
      if (res.ok) return res.json()
      return res.json().then(json => Promise.reject(json))
    })
  }, dependencies)
}

Conclusion

Les Hooks personnalisés sont un puissant moyen d’enrichir vos applications React. Ils offrent une grande flexibilité et vous permettent de construire des composants plus propres et plus expressifs. Ils ont été créés pour répondre à tous vos besoins.

En résumé, les Hooks personnalisés vous donnent les outils pour abstraire et réutiliser la logique d’état dans vos applications, tout en gardant votre code lisible et maintenable. N’hésitez pas à expérimenter et à créer vos propres Hooks pour répondre aux défis uniques de vos projets React.

UNE QUESTION ? UN PROJET ? UN AUDIT DE CODE / D'INFRASTRUCTURE ?

Pour vos besoins d’expertise que vous ne trouvez nulle part ailleurs, n’hésitez pas à nous contacter.

ILS SE SONT FORMÉS CHEZ NOUS

partenaire sncf
partenaire hp
partenaire allianz
partenaire sfr
partenaire engie
partenaire boursorama
partenaire invivo
partenaire orange
partenaire psa
partenaire bnp
partenaire sncf
partenaire hp
partenaire allianz
partenaire sfr
partenaire engie
partenaire boursorama
partenaire invivo
partenaire orange
partenaire psa
partenaire bnp