Les fermetures ne sont pas un problème de React. Elles sont de la JavaScript normale. Elles deviennent un problème de mémoire uniquement lorsqu'un autre système maintient un callback en vie après que le composant qui l'a créé aurait dû disparaître.
C'est pourquoi les mêmes bogues continuent de réapparaître sous différentes formes :
- écouteurs d'événements
- intervalles
- abonnements
- observateurs
Une forme typique de fuite
Le problème ressemble généralement à ceci :
useEffect(() => {
function onResize() {
setWidth(window.innerWidth);
}
window.addEventListener("resize", onResize);
}, []);
Si l'écouteur n'est jamais supprimé, le callback peut garder des références à l'état du composant et aux fonctions de mise à jour plus longtemps que prévu. Une fuite peut sembler petite. Une navigation répétée à travers le même écran peut la transformer en une montée constante de la consommation mémoire.
Le schéma correct maintient l'enregistrement et le nettoyage ensemble :
useEffect(() => {
function onResize() {
setWidth(window.innerWidth);
}
window.addEventListener("resize", onResize);
return () => window.removeEventListener("resize", onResize);
}, []);
Ce qu'il faut inspecter dans les applications réelles
Lorsque la mémoire augmente après des changements de route ou de longues sessions, commencez par les callbacks à long terme qui capturent l'état du composant. La question est simple : qui détient encore cette fermeture ?
Cette enquête mène généralement à :
- écouteurs de navigateur
- abonnements de bibliothèque
- observateurs non fermés
- bus d'événements personnalisés
Meilleure règle d'ingénierie
Chaque fois qu'un effet enregistre un callback en dehors de React, écrivez le chemin de nettoyage dans le même effet avant de passer à autre chose. Cette habitude empêche plus de fuites que n'importe quelle session de profilage ultérieure.
Lectures supplémentaires