Hooks personnalisés : extraire une logique réutilisable
Déplacez la logique avec état dans des fonctions use* personnalisées pour partager le comportement entre les composants sans dupliquer le code ni remonter l’état.
Hooks personnalisés : extraire une logique réutilisable est une leçon Frontend Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Frontend Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Frontend Academy comprend 4 leçons au total.
Que sont les fonctions personnalisées ?
Une fonction personnalisée est une fonction JavaScript dont le nom commence par use et qui appelle d'autres fonctions de ce type en interne. Les fonctions personnalisées permettent d'extraire une logique avec état afin que plusieurs composants puissent la partager sans copier-coller.
Extraire la logique dans une fonction personnalisée
Repérez la logique dupliquée entre les composants (récupération + chargement + erreur, taille de la fenêtre, stockage local) et déplacez-la dans une fonction personnalisée.
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handler = () => setWidth(window.innerWidth);
window.addEventListener('resize', handler);
return () => window.removeEventListener('resize', handler);
}, []);
return width;
}
// Usage:
const width = useWindowWidth();
const isMobile = width < 768;useFetch — Fonction de récupération des données
Une fonction réutilisable de récupération de données que tout composant peut utiliser pour charger des données depuis une URL.
function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const controller = new AbortController();
async function load() {
try {
const res = await fetch(url, { signal: controller.signal });
if (!res.ok) throw new Error(`${res.status}`);
setData(await res.json());
} catch (err) {
if ((err as DOMException).name !== 'AbortError')
setError((err as Error).message);
} finally { setLoading(false); }
}
load();
return () => controller.abort();
}, [url]);
return { data, loading, error };
}Fonction useLocalStorage
Une fonction personnalisée qui synchronise une valeur avec localStorage et la maintient synchronisée entre les onglets grâce à l'événement de stockage.
function useLocalStorage<T>(key: string, initialValue: T) {
const [value, setValue] = useState<T>(() => {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initialValue;
});
const set = useCallback((newValue: T) => {
setValue(newValue);
localStorage.setItem(key, JSON.stringify(newValue));
}, [key]);
return [value, set] as const;
}Les fonctions personnalisées partagent la logique, pas l'état
Chaque composant qui appelle une fonction personnalisée possède son propre état indépendant. Les fonctions ne sont pas des instances uniques : ce sont des appels de fonction qui créent des instances d'état isolées.
Conventions de nommage
Les noms des fonctions personnalisées doivent commencer par use. Cette règle est imposée par les règles d'analyse statique d'ESLint pour les fonctions de ce type, qui vérifient qu'elles sont appelées au niveau supérieur et dans le bon ordre.
Renvoyer plusieurs valeurs
Les fonctions personnalisées renvoient généralement un objet (valeurs nommées) ou un tuple (comme useState). Les tuples permettent une déstructuration avec des noms personnalisés ; les objets sont explicites.
// Tuple (like useState):
const [value, setValue] = useLocalStorage('key', 0);
// Object (more descriptive):
const { data, loading, error, refetch } = useFetch('/api/users');Fonction useDebounce
Retardez la mise à jour d'une valeur : mettez-la à jour uniquement après que l'utilisateur a cessé de taper pendant un délai défini.
function useDebounce<T>(value: T, delay: number): T {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebounced(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debounced;
}
// Usage:
const debouncedSearch = useDebounce(searchTerm, 300);
useEffect(() => { search(debouncedSearch); }, [debouncedSearch]);Fonction useMediaQuery
Encapsule window.matchMedia dans une fonction personnalisée pour lire de manière réactive les résultats des requêtes média CSS.
function useMediaQuery(query: string): boolean {
const [matches, setMatches] = useState(() => window.matchMedia(query).matches);
useEffect(() => {
const mq = window.matchMedia(query);
const handler = (e: MediaQueryListEvent) => setMatches(e.matches);
mq.addEventListener('change', handler);
return () => mq.removeEventListener('change', handler);
}, [query]);
return matches;
}Tester les fonctions personnalisées
Utilisez l'utilitaire renderHook() de @testing-library/react pour tester les fonctions personnalisées de manière isolée, sans les encapsuler dans un composant.
import { renderHook, act } from '@testing-library/react';
test('useCounter increments', () => {
const { result } = renderHook(() => useCounter(0));
expect(result.current.count).toBe(0);
act(() => result.current.increment());
expect(result.current.count).toBe(1);
});Bibliothèques publiées de fonctions personnalisées
Les bibliothèques communautaires de fonctions personnalisées fournissent des centaines de fonctions éprouvées : @uidotdev/usehooks, react-use, usehooks-ts. Avant d'écrire une fonction personnalisée, vérifiez si une version bien éprouvée existe déjà.
Vérification rapide
Qu'advient-il de l'état contenu dans une fonction personnalisée lorsqu'elle est appelée par deux composants différents ?
Récapitulatif : fonctions personnalisées
Les fonctions personnalisées extraient une logique avec état pour la réutiliser. Nommez-les avec le préfixe use. Chaque composant qui appelle la fonction obtient un état indépendant. Renvoyez des objets ou des tuples. Modèles courants : useFetch, useLocalStorage, useDebounce, useMediaQuery. Testez avec renderHook(). Consultez les bibliothèques communautaires avant de tout écrire vous-même.
Questions Fréquemment Posées
La leçon « Hooks personnalisés : extraire une logique réutilisable » est-elle gratuite ?
Oui — le texte complet de « Hooks personnalisés : extraire une logique réutilisable » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Frontend Academy, passe à CoddyKit PRO. Le cours Frontend Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Hooks personnalisés : extraire une logique réutilisable » ?
Déplacez la logique avec état dans des fonctions use* personnalisées pour partager le comportement entre les composants sans dupliquer le code ni remonter l’état. Tu pratiques Frontend Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Frontend Academy ?
Aucune expérience préalable n'est requise. Frontend Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.
Combien de temps prend la leçon « Hooks personnalisés : extraire une logique réutilisable » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Frontend Academy ?
Oui. Chaque leçon Frontend Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- useContext pour l’état global
- useReducer pour les états complexes
- useMemo et useCallback pour les performances
- Hooks personnalisés : extraire une logique réutilisable