Génération de Hooks de Données
Crée des Custom Hooks de fetching et de mutation (SWR / React Query) par l'IA, du boilerplate zéro.
4.1Les sorts de convocation
Un hook de données, c'est comme un allié invoqué qui se charge de gérer une ressource pour toi. Tu appelles usePosts() et en échange, tu reçois les données, l'état de chargement et les erreurs, sans avoir écrit une seule ligne de fetch, useEffect ou useState.
4.2Générer un hook SWR depuis une spécification
Tu es un dev React/TypeScript senior.
Génère un custom hook "usePosts" qui :
- Fetch les articles depuis /wp-json/wp/v2/posts
- Utilise SWR pour le cache et la revalidation
- Supporte ces paramètres : page, perPage, categoryId, search (tous optionnels)
- Retourne : { posts, isLoading, isError, pagination }
- Valide les données avec le WpPostSchema Zod (importé depuis @/lib/types/schemas)
- Gère les erreurs réseau et les erreurs de validation séparément
Types d'entrée et de sortie stricts en TypeScript.
Le hook doit être pur, sans side effects autres que fetch.import useSWR from 'swr';
import { z } from 'zod';
import { WpPostSchema } from '@/lib/types/schemas/post.schema';
const WpPostArraySchema = z.array(WpPostSchema);
type WpPost = z.infer<typeof WpPostSchema>;
interface UsePostsParams {
page?: number;
perPage?: number;
categoryId?: number;
search?: string;
}
interface UsePostsReturn {
posts: WpPost[] | undefined;
isLoading: boolean;
isError: Error | null;
pagination: { page: number; totalPages: number } | null;
}
function buildUrl(params: UsePostsParams): string {
const url = new URL('/wp-json/wp/v2/posts', window.location.origin);
url.searchParams.set('_embed', '1');
if (params.page) url.searchParams.set('page', String(params.page));
if (params.perPage) url.searchParams.set('per_page', String(params.perPage));
if (params.categoryId) url.searchParams.set('categories', String(params.categoryId));
if (params.search) url.searchParams.set('search', params.search);
return url.toString();
}
async function fetcher(url: string) {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
const raw = await res.json();
const parsed = WpPostArraySchema.safeParse(raw);
if (!parsed.success) {
throw new Error('Contrat API invalide: ' + parsed.error.message);
}
return {
posts: parsed.data,
totalPages: Number(res.headers.get('X-WP-TotalPages') ?? 1),
};
}
export function usePosts(params: UsePostsParams = {}): UsePostsReturn {
const url = buildUrl(params);
const { data, error, isLoading } = useSWR(url, fetcher, {
revalidateOnFocus: false,
keepPreviousData: true,
});
return {
posts: data?.posts,
isLoading,
isError: error ?? null,
pagination: data ? { page: params.page ?? 1, totalPages: data.totalPages } : null,
};
}4.3Générer un hook de mutation React Query
Pour les mutations (créer, modifier, supprimer), React Query avec useMutation est le standard. Voici le prompt adapté :
Génère un custom hook "useUpdatePost" avec React Query (@tanstack/react-query).
Action : PUT /wp-json/wp/v2/posts/:id
Corps : Partial<WpPost> (titre, contenu, statut seulement)
Auth : Bearer token dans le header (récupéré depuis useAuthStore - Zustand)
Le hook retourne :
- mutate(id, data) - déclenche la mutation
- isLoading, isSuccess, isError, error
- Invalide le cache SWR de la liste des posts après succès
Gestion d'erreurs : distingue 401 (non autorisé), 404 (introuvable), 422 (validation).import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useAuthStore } from '@/lib/stores/auth-store';
import type { WpPost } from '@/lib/types/schemas/post.schema';
type UpdatePostInput = {
id: number;
data: Pick<Partial<WpPost>, 'title' | 'content' | 'status'>;
};
class ApiError extends Error {
constructor(public status: number, message: string) {
super(message);
}
}
async function updatePost({ id, data }: UpdatePostInput, token: string): Promise<WpPost> {
const res = await fetch(`/wp-json/wp/v2/posts/${id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
},
body: JSON.stringify(data),
});
if (res.status === 401) throw new ApiError(401, 'Session expirée, reconnecte-toi.');
if (res.status === 404) throw new ApiError(404, 'Article introuvable.');
if (res.status === 422) throw new ApiError(422, 'Données invalides.');
if (!res.ok) throw new ApiError(res.status, 'Erreur serveur.');
return res.json();
}
export function useUpdatePost() {
const queryClient = useQueryClient();
const token = useAuthStore((s) => s.token);
return useMutation({
mutationFn: (input: UpdatePostInput) => updatePost(input, token ?? ''),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['posts'] });
},
});
}Génération en lot
Pour générer tous tes hooks d'un coup, donne à l'IA ta liste d'endpoints avec leurs méthodes et types, et demande-lui de créer un fichier par ressource. Tu passes de 2h de boilerplate à 5 minutes.
Génère un hook SWR [de lecture] pour chacun de ces endpoints :
- GET /wp/v2/posts → list + single
- GET /wp/v2/categories → list
- GET /wp/v2/users/me → profil connecté
Utilise le même pattern fetcher + Zod que le hook usePosts que je t'ai montré.