React
Hooks
TypeScript
React Hooks : Patterns avancés pour la production
Découvrez les patterns de hooks les plus utiles — debounce, localStorage, media queries, et custom hooks réutilisables.
Emmanuel Mulonda5 juillet 20268 min de lecture
Introduction
Les hooks sont le cœur de React. Voici les patterns que j'utilise dans chaque projet de production.
useDebounce
Délayez une valeur pour éviter les appels API excessifs :
import { useState, useEffect } from "react";
export function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}
// Usage
const [search, setSearch] = useState("");
const debouncedSearch = useDebounce(search, 300);
useLocalStorage
Persistance dans le localStorage avec typage :
import { useState, useEffect } from "react";
export function useLocalStorage<T>(key: string, initialValue: T) {
const [value, setValue] = useState<T>(() => {
if (typeof window === "undefined") return initialValue;
try {
const item = window.localStorage.getItem(key);
return item ? (JSON.parse(item) as T) : initialValue;
} catch {
return initialValue;
}
});
useEffect(() => {
window.localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue] as const;
}
useMediaQuery
Écoutez les changements de viewport :
import { useEffect, useState } from "react";
export function useMediaQuery(query: string): boolean {
const [matches, setMatches] = useState(() => {
if (typeof window === "undefined") return false;
return window.matchMedia(query).matches;
});
useEffect(() => {
const media = window.matchMedia(query);
const listener = (e: MediaQueryListEvent) => setMatches(e.matches);
media.addEventListener("change", listener);
return () => media.removeEventListener("change", listener);
}, [query]);
return matches;
}
// Usage
const isMobile = useMediaQuery("(max-width: 768px)");
const prefersDark = useMediaQuery("(prefers-color-scheme: dark)");
useIntersectionObserver
Détection de visibilité pour le lazy loading :
import { useEffect, useRef, useState } from "react";
export function useIntersectionObserver(threshold = 0.1) {
const ref = useRef<HTMLDivElement>(null);
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
observer.disconnect();
}
},
{ threshold },
);
if (ref.current) observer.observe(ref.current);
return () => observer.disconnect();
}, [threshold]);
return { ref, isVisible };
}
useFetch
Wrapper fetch avec loading, error et data :
React
Hooks
TypeScript