Si vous développez en React, vous avez forcément déjà copié-collé de la logique entre plusieurs composants.
Même useEffect. Même useState. Même appel API.
C’est exactement pour éviter ça qu’on crée des hooks React personnalisés.
Dans ce guide complet, vous allez apprendre :
- ✅ Comment créer un hook React personnalisé
- ✅ Les règles à respecter
- ✅ Des exemples concrets en TypeScript
- ✅ Les erreurs fréquentes
- ✅ Comment optimiser vos hooks pour la performance
TL;DR – C’est quoi un hook React personnalisé ?
Un hook React personnalisé est :
- Une fonction JavaScript
- Qui commence par "use"
- Qui utilise d'autres hooks React (useState, useEffect, etc.)
- Qui permet de réutiliser une logique métier
Il améliore la lisibilité, la maintenabilité et l’architecture de votre application.
Pourquoi créer un hook React personnalisé ?
Sans hook :
- Code dupliqué
- Logique éparpillée
- Maintenance difficile
Avec un hook :
- Logique centralisée
- Réutilisable
- Testable
- Plus propre
C’est une base essentielle pour une architecture React moderne.
Exemple 1 – useCounter (hook React simple)
import { useState } from "react";
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
const increment = () => setCount(c => c + 1);
const decrement = () => setCount(c => c - 1);
const reset = () => setCount(initialValue);
return { count, increment, decrement, reset };
}
Utilisation
function Counter() {
const { count, increment, decrement, reset } = useCounter(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
<button onClick={reset}>Reset</button>
</div>
);
}
Exemple 2 – Hook React avec localStorage (useLocalStorage)
Cas d’usage courant : sauvegarder des préférences utilisateur.
import { useState } from "react";
function useLocalStorage<T>(key: string, initialValue: T) {
const [storedValue, setStoredValue] = useState<T>(() => {
if (typeof window === "undefined") return initialValue;
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch {
return initialValue;
}
});
const setValue = (value: T | ((val: T) => T)) => {
const valueToStore =
value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
if (typeof window !== "undefined") {
window.localStorage.setItem(key, JSON.stringify(valueToStore));
}
};
return [storedValue, setValue] as const;
}
⚠️ Important si vous utilisez Next.js : Toujours vérifier que window existe (SSR).
Exemple 3 – Hook React pour appel API (useApi)
import { useState, useEffect } from "react";
function useApi<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
const controller = new AbortController();
const fetchData = async () => {
try {
setLoading(true);
const response = await fetch(url, { signal: controller.signal });
if (!response.ok) throw new Error("Network error");
const result = await response.json();
setData(result);
} catch (err) {
if ((err as any).name !== "AbortError") {
setError(err as Error);
}
} finally {
setLoading(false);
}
};
fetchData();
return () => controller.abort();
}, [url]);
return { data, loading, error };
}
Optimisation ajoutée :
- AbortController
- Protection contre memory leak
Exemple 4 – Hook React performance : useDebounce
import { useEffect, useState } from "react";
function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(handler);
}, [value, delay]);
return debouncedValue;
}
Utilisation typique :
- Barre de recherche
- Appel API optimisé
- Filtrage dynamique
Règles importantes des hooks React
- Ne pas appeler un hook dans une condition
- Toujours respecter l’ordre d’appel
- Toujours commencer par "use"
- Respecter les dépendances dans useEffect
Sinon : 👉 Erreur “Invalid Hook Call”
Erreurs fréquentes avec les hooks personnalisés
❌ Hook trop complexe ❌ Trop de responsabilités dans un seul hook ❌ Mauvaise gestion des dépendances ❌ Ignorer le SSR ❌ Ne pas tester le hook
Tester un hook React
import { renderHook, act } from '@testing-library/react';
import { useCounter } from './useCounter';
test('should increment counter', () => {
const { result } = renderHook(() => useCounter());
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});
FAQ – Hooks React personnalisés
Comment créer un hook React personnalisé ?
Créez une fonction qui commence par "use" et utilisez des hooks React à l’intérieur pour encapsuler une logique réutilisable.
Peut-on utiliser TypeScript avec des hooks React ?
Oui, et c’est recommandé pour typer les paramètres et le retour.
Les hooks fonctionnent-ils avec Next.js ?
Oui, mais attention au SSR (window, localStorage).
Quelle est la différence entre un hook et un composant ?
Un hook contient de la logique, un composant contient de l’interface utilisateur.
Conclusion
Maîtriser les hooks React personnalisés est essentiel pour :
- Structurer votre application
- Réduire la duplication
- Améliorer la performance
- Construire une architecture scalable
👉 Besoin d’aide pour structurer un projet React ou Next.js performant ? Découvrez nos services de développement et d’optimisation.
