Contactez-nous

Exemples : `useFetch`, `useLocalStorage`, `useToggle`, `useFormInput`

Découvrez des exemples pratiques de Hooks personnalisés (Custom Hooks) React populaires : useFetch, useLocalStorage, useToggle, useFormInput avec leur code et utilisation.

Introduction : Voir les Custom Hooks en action

Après avoir compris la motivation et les règles de création des Hooks personnalisés, rien ne vaut des exemples concrets pour saisir leur utilité et leur fonctionnement. Nous allons explorer ici quatre exemples courants de Hooks personnalisés qui résolvent des problèmes récurrents dans le développement React :

  • useFetch : Pour la récupération de données asynchrone.
  • useLocalStorage : Pour la persistance de l'état dans le stockage local du navigateur.
  • useToggle : Pour gérer facilement un état booléen.
  • useFormInput : Pour simplifier la gestion de l'état des champs de formulaire.

Ces exemples illustrent comment encapsuler une logique spécifique et la rendre réutilisable à travers différents composants.

Exemple 1 : `useFetch`

Objectif : Encapsuler la logique de récupération de données depuis une URL, en gérant les états de chargement, les données reçues et les erreurs éventuelles.

Définition du Hook (`hooks/useFetch.js`) :
import { useState, useEffect } from 'react';

function useFetch(url, options = {}) {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    if (!url) {
      setIsLoading(false);
      setData(null);
      setError(null);
      return;
    }

    const controller = new AbortController();
    const signal = controller.signal;

    const fetchData = async () => {
      setIsLoading(true);
      setData(null);
      setError(null);
      try {
        const response = await fetch(url, { ...options, signal });
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        const result = await response.json();
        if (!signal.aborted) {
          setData(result);
        }
      } catch (fetchError) {
        if (fetchError.name !== 'AbortError' && !signal.aborted) {
          setError(fetchError.message);
        }
      } finally {
        if (!signal.aborted) {
          setIsLoading(false);
        }
      }
    };

    fetchData();

    // Cleanup function to abort fetch on unmount or url change
    return () => {
      controller.abort();
    };
  }, [url, JSON.stringify(options)]); // Re-run if url or options change (stringify for deep comparison)

  return { data, isLoading, error };
}

export default useFetch;
Utilisation :
import React from 'react';
import useFetch from './hooks/useFetch';

function PostDisplay({ postId }) {
  const { data: post, isLoading, error } = useFetch(
    `https://jsonplaceholder.typicode.com/posts/${postId}`
  );

  if (isLoading) return 

Chargement du post...

; if (error) return

Erreur : {error}

; if (!post) return null; return (

{post.title}

{post.body}

); }

Exemple 2 : `useLocalStorage`

Objectif : Fournir une interface similaire à `useState`, mais qui synchronise automatiquement la valeur avec le `localStorage` du navigateur.

Définition du Hook (`hooks/useLocalStorage.js`) :
import { useState, useEffect } from 'react';

function getStorageValue(key, defaultValue) {
  if (typeof window === 'undefined') return defaultValue; // Pour SSR
  const saved = localStorage.getItem(key);
  try {
    return saved !== null ? JSON.parse(saved) : defaultValue;
  } catch (error) {
    console.error("Error parsing localStorage key “", key, "”:", error);
    return defaultValue;
  }
}

function useLocalStorage(key, defaultValue) {
  const [value, setValue] = useState(() => {
    return getStorageValue(key, defaultValue);
  });

  useEffect(() => {
    if (typeof window !== 'undefined') {
      localStorage.setItem(key, JSON.stringify(value));
    }
  }, [key, value]);

  return [value, setValue];
}

export default useLocalStorage;
Utilisation :
import React from 'react';
import useLocalStorage from './hooks/useLocalStorage';

function UserPreferences() {
  const [username, setUsername] = useLocalStorage('username', 'Invité');

  return (
    

Nom stocké : {username}

); }

Exemple 3 : `useToggle`

Objectif : Simplifier la gestion d'un état booléen en fournissant directement une fonction pour inverser sa valeur.

Définition du Hook (`hooks/useToggle.js`) :
import { useState, useCallback } from 'react';

function useToggle(initialState = false) {
  const [state, setState] = useState(initialState);

  // Utilise useCallback pour mémoriser la fonction toggle
  const toggle = useCallback(() => {
    setState(prevState => !prevState);
  }, []);

  // Retourne l'état et la fonction toggle
  return [state, toggle];
}

export default useToggle;
Utilisation :
import React from 'react';
import useToggle from './hooks/useToggle';

function CollapsibleSection({ title, children }) {
  const [isOpen, toggleOpen] = useToggle(false); // Initialement fermé

  return (
    

{title} {isOpen ? '[-]' : '[+]'}

{isOpen &&
{children}
}
); }

Exemple 4 : `useFormInput`

Objectif : Encapsuler la logique de base pour un champ de formulaire contrôlé (valeur + gestionnaire `onChange`).

Définition du Hook (`hooks/useFormInput.js`) :
import { useState, useCallback } from 'react';

function useFormInput(initialValue = '') {
  const [value, setValue] = useState(initialValue);

  const handleChange = useCallback((event) => {
    setValue(event.target.value);
  }, []);

  // Retourne la valeur et le gestionnaire pour les props de l'input
  // et potentiellement une fonction reset
  const reset = useCallback(() => setValue(initialValue), [initialValue]);

  return {
    value,          // Pour la prop 'value' de l'input
    onChange: handleChange, // Pour la prop 'onChange' de l'input
    reset           // Fonction pour réinitialiser
  };
}

export default useFormInput;
Utilisation :
import React from 'react';
import useFormInput from './hooks/useFormInput';

function SimpleForm() {
  const nameInputProps = useFormInput('John Doe');
  const emailInputProps = useFormInput('');

  const handleSubmit = (event) => {
    event.preventDefault();
    alert(`Nom: ${nameInputProps.value}, Email: ${emailInputProps.value}`);
    // nameInputProps.reset(); // Optionnel : réinitialiser après soumission
    // emailInputProps.reset();
  };

  return (
    


); }

Conclusion : Blocs de construction logiques

Ces exemples montrent comment les Hooks personnalisés peuvent encapsuler des logiques variées, de la récupération de données complexe à la simple gestion d'un booléen. En créant ces fonctions réutilisables, vous simplifiez vos composants, réduisez la duplication de code et rendez votre application plus facile à comprendre et à maintenir.

N'hésitez pas à créer vos propres Hooks personnalisés dès que vous identifiez une logique stateful répétitive dans votre code. C'est une pratique fondamentale pour écrire du code React propre et efficace.