Effets de bord et récupération de données — useEffect
Dans ce chapitre, vous apprendrez le Hook d'effet de bord le plus important de React — useEffect, et utiliserez fetch pour charger les données du blog depuis un fichier JSON au bon moment.
Qu'est-ce qu'un effet de bord ?
En React,un effet de borddésigne des opérations sans rapport avec le rendu :
- Demander des données au serveur
- Manipuler localStorage
- Définir des minuteurs avec setInterval
- Modifier manuellement le DOM
- S'abonner à des événements externes
Les effets de bord ne peuvent pas être exécutés directement dans le corps de la fonction du composant (ce qui les ferait s'exécuter à chaque rendu) ; ils doivent être placés dansuseEffect.
Utilisation de base de useEffect
Exemple
function HomePage() {
const [message, setMessage] = useState('Loading...')
// useEffect(fn, deps) : exécute l'effet secondaire après le rendu du composant
useEffect(() => {
console.log('Le composant a été monté dans le DOM ; les effets secondaires peuvent maintenant être exécutés.')
setMessage('Chargement des données terminé !')
}, []) // Tableau de dépendances vide = s'exécute une seule fois après le rendu initial
return <p>{message}</p>
}
Trois façons d'écrire le tableau de dépendances
| Syntaxe | Moment d'exécution | Cas d'utilisation |
|---|---|---|
useEffect(fn) | S'exécute après chaque rendu | Rarement utilisé ; sujet aux boucles infinies |
useEffect(fn, []) | S'exécute une seule fois après le rendu initial | Chargement des données, initialisation de bibliothèques tierces |
useEffect(fn, [dep]) | S'exécute après le rendu initial + lorsque dep change | Écouter les changements de données spécifiques et exécuter les opérations correspondantes |
Différence entre omettre le tableau de dépendances et un tableau vide :
useEffect(fn)S'exécute après chaque rendu ;useEffect(fn, [])Il ne s'exécute qu'une seule fois après le rendu initial. La première peut facilement provoquer des boucles infinies (setState dans l'effet → déclenche un rendu → l'effet s'exécute à nouveau → ...), il n'est donc presque jamais utilisé.
Chargement de données JSON avec fetch
Tout comme Vue3, nous plaçons les données de l'article dans lepublic/posts.jsonfichier.
Étape 1 : Créer le fichier de données
Exemple
[
{
"id": 1,
"title": "Le guide complet pour bien démarrer avec React",
"summary": "Apprenez les Hooks React à partir de zéro, en couvrant les concepts fondamentaux tels que useState et useEffect.",
"content": "<h2>Pourquoi apprendre React ?</h2><p>React est l'un des frameworks front-end les plus populaires...</p>",
"category": "React",
"date": "2024-05-10"
},
{
"id": 2,
"title": "Programmation asynchrone en JavaScript expliquée",
"summary": "Comprenez Promise, async/await, la boucle d’événements et la file des microtâches en un seul article.",
"content": "<h2>Qu’est-ce que l’asynchrone ?</h2><p>JS est monothread...</p>",
"category": "JavaScript",
"date": "2024-05-08"
},
{
"id": 3,
"title": "CSS Grid Layout en pratique",
"summary": "Implémentez facilement des mises en page responsives complexes avec CSS Grid.",
"content": "<h2>Premiers pas avec Grid</h2><p>Grid est un système de mise en page bidimensionnel...</p>",
"category": "CSS",
"date": "2024-05-05"
}
]
Étape 2 : Charger les données dans useEffect
Exemple
import { useState, useEffect, useMemo } from 'react'
import BlogCard from '../components/BlogCard'
import CategoryFilter from '../components/CategoryFilter'
function HomePage() {
const [articles, setArticles] = useState([]) // Données des articles
const [isLoading, setIsLoading] = useState(true) // État de chargement
const [error, setError] = useState(null) // Message d'erreur
const [activeCategory, setActiveCategory] = useState('Toutes')
// useEffect charge les données : tableau de dépendances vide = ne s'exécute qu'une seule fois après le rendu initial
useEffect(() => {
let cancelled = false // Indicateur pour empêcher setState après le démontage du composant
async function fetchPosts() {
setIsLoading(true)
setError(null)
try {
const res = await fetch('/posts.json')
if (!res.ok) throw new Erreur(`HTTP ${res.status}`)
const data = await res.json()
if (!cancelled) {
setArticles(data)
}
} catch (err) {
if (!cancelled) {
setError(err.message)
}
} finally {
if (!cancelled) {
setIsLoading(false)
}
}
}
fetchPosts()
// Fonction de nettoyage : définir cancelled sur true lorsque le composant est démonté
return () => { cancelled = true }
}, [])
const categories = useMemo(() => {
return ['Toutes', ...new Set(articles.map(a => a.category))]
}, [articles])
const filteredArticles = useMemo(() => {
if (activeCategory === 'Tous') return articles
return articles.filter(a => a.category === activeCategory)
}, [articles, activeCategory])
return (
<div>
<h2 className="section-title">Derniers articles</h2>
{/* Chargement */}
{isLoading && <p className="status-msg">Chargement, veuillez patienter...</p>}
{/* Erreur de chargement */}
{error && (
<div className="status-msg error">
<p>Échec du chargement :{error}</p>
<button onClick={() => window.location.reload()}>Réessayer</button>
</div>
)}
{/* Chargement des données terminé */}
{!isLoading && !error && (
<>
<CategoryFilter
categories={categories}
activeCategory={activeCategory}
onCategoryChange={setActiveCategory}
/>
<p className="result-info">common{filteredArticles.length}article</p>
{filteredArticles.length === 0 ? (
<p className="empty-tip">Aucun article dans cette catégorie pour le moment</p>
) : (
<div className="article-grid">
{filteredArticles.map(article => (
<BlogCard key={article.id} {...article} />
))}
</div>
)}
</>
)}
</div>
)
}
export default HomePage
cancelledL'utilisation d'un drapeau est un modèle courant dans React. Lorsque fetch est toujours en cours et que l'utilisateur quitte la page (le composant est démonté), le setState suivant signalera un avertissement d'erreur. Le définir dans la fonction de nettoyagecancelled = truepermet d'éviter setState après le démontage.
Fonction de nettoyage
La fonction de rappel de useEffect peut renvoyer une fonction, appelée lafonction de nettoyage。
Il s'exécute à deux moments :Lorsque le composant est démontéetAvant l'exécution de l'effet suivant。
Exemple
// Effet secondaire : s'abonner aux événements
const handleScroll = () => console.log('Scrolled')
window.addEventListener('scroll', handleScroll)
// Retourner la fonction de nettoyage
return () => {
// Supprimer automatiquement l'écouteur d'événement lorsque le composant est démonté pour éviter les fuites de mémoire
window.removeEventListener('scroll', handleScroll)
}
}, [])
useEffect(() => {
// Effet secondaire : définir un minuteur
const timer = setInterval(() => {
console.log('Executes every second')
}, 1000)
return () => clearInterval(timer) // Arrêter le minuteur
}, [])
| Effet secondaire | Nécessite un nettoyage ? | Méthode de nettoyage |
|---|---|---|
| requête fetch | Oui | Utiliser un indicateur cancelled ou AbortController |
| Écouteur d'événement | Oui | removeEventListener |
| Minuteur | Oui | clearInterval / clearTimeout |
| Modifier le DOM puis restaurer | Oui | Restaurer l'état d'origine lors du nettoyage |
| Écritures dans localStorage | non | Aucun nettoyage nécessaire |
Quatre états pour la gestion des requêtes asynchrones
Toute requête de données doit couvrir les quatre états UI suivants :
| State | Condition | UI |
|---|---|---|
| Chargement | isLoading === true | Animation de chargement, écran squelette |
| Succès | Les données ont été retournées | Afficher le contenu normalement |
| Failure | error !== null | Message d'erreur + bouton de nouvelle tentative |
| Données vides | Les données sont un tableau vide | Message d'état vide |
Comparaison avec le cycle de vie de Vue3
| Vue3 | React | Description |
|---|---|---|
onMounted | useEffect(fn, []) | S'exécute après le rendu initial |
watch(keyword, fn) | useEffect(fn, [keyword]) | Réagit à des changements de données spécifiques |
onBeforeUnmount | useEffect 的 cleanup | Nettoyage avant la destruction du composant |
| Aucun équivalent direct | useEffect(() => { fn; return cleanup }, [dep]) | Lorsque dep change, exécutez d'abord le nettoyage, puis fn |
Résumé du chapitre
Dans ce chapitre, vous avez maîtrisé l'utilisation essentielle de useEffect : les trois façons d'écrire le tableau de dépendances, le chargement asynchrone des données avec fetch, la gestion des quatre états de l'interface, et le rôle de la fonction de nettoyage.
Désormais, les données du blog sont chargées dynamiquement depuis un fichier JSON externe, elles ne sont plus codées en dur en JS.
Autres extensions