Introduction aux hooks personnalisés
Les hooks personnalisés sont des fonctions réutilisables dans React qui encapsulent une logique spécifique, identifiées par le préfixe "use". Ils permettent de partaegr du code entre composants sans duplication, et peuvent interagir avec d'autres hooks come useState ou useEffect.
Exemple 1 : Traitement d'URL
Ce hook extrait les paramètres de requête d'une chaîne URL en utilisant l'API URL native, évitant ainsi des dépendances externes.
import React, { useState } from 'react';
function useUrlParser(urlString) {
const urlObject = new URL(urlString);
const searchParams = new URLSearchParams(urlObject.search);
const queryParams = {};
for (const [key, value] of searchParams.entries()) {
queryParams[key] = value;
}
return queryParams;
}
function DemoComponent() {
const extractedParams = useUrlParser('https://example.com/product?id=42&category=electronics#section');
const [params, setParams] = useState(extractedParams);
console.log('Paramètres extraits :', params);
return (
<div>
<h5>Utilisation du hook d'URL</h5>
</div>
);
}
Exemple 2 : Formatage de date
Ce hook transforme une date en un format lisible avec un séparateur configurable et inclut le jour de la semaine en français.
function addLeadingZero(number) {
if (isNaN(number)) return '00';
return number < 10 ? '0' + number : String(number);
}
function useDateFormatter(timestamp, separator = '/') {
const dateObj = new Date(timestamp);
const weekdays = ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'];
const year = dateObj.getFullYear();
const month = addLeadingZero(dateObj.getMonth() + 1);
const day = addLeadingZero(dateObj.getDate());
const weekday = weekdays[dateObj.getDay()];
return `${year}${separator}${month}${separator}${day} ${weekday}`;
}
// Utilisation dans un composant
const formatted = useDateFormatter(Date.now(), '-');
const [displayDate, setDisplayDate] = useState(formatted);
Exemple 3 : Requête API avec valiadtion des données
Ce hook gère les appels Axios, gère les états de chargement et d'erreur, et intègre une validation du type de données reçues pour assurer la robustesse de l'interface.
import axios from 'axios';
import React, { useState, useEffect } from 'react';
function useApiRequest(endpoint) {
const [apiData, setApiData] = useState(null);
const [apiError, setApiError] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
axios.get(endpoint)
.then(response => {
setApiData(response.data);
})
.catch(err => {
setApiError(err.message);
})
.finally(() => {
setIsLoading(false);
});
}, [endpoint]);
return { apiData, apiError, isLoading };
}
function checkDataStructure(data) {
if (typeof data !== 'object' || data === null) {
return { type: 'non-object', value: data };
}
if (Array.isArray(data)) {
return { type: 'array', value: data.length > 0 ? data : null };
}
return { type: 'object', value: Object.keys(data).length > 0 ? data : null };
}
function renderStatus(type, loading, error) {
if (loading) return <p>Chargement en cours...</p>;
if (error) return <p>Erreur : {error}</p>;
if (type === 'non-object') return <p>Données invalides</p>;
if (type === 'array' && !loading) return <p>Tableau vide</p>;
if (type === 'object' && !loading) return <p>Objet vide</p>;
return null;
}
function DataComponent() {
const { apiData, apiError, isLoading } = useApiRequest('/api/data');
const validationResult = checkDataStructure(apiData);
const statusMessage = renderStatus(validationResult.type, isLoading, apiError);
if (isLoading || apiError || !validationResult.value) {
return <div>{statusMessage || 'Aucune donnée disponible'}</div>;
}
return (
<div>
<h5>Résultat de la requête</h5>
{JSON.stringify(validationResult.value, null, 2)}
</div>
);
}