J'ai appris React et j'ai lu que la fonction renvoyée par useEffect
est destinée à faire le nettoyage et React effectue le nettoyage lorsque le le composant se démonte.
J'ai donc expérimenté un peu mais j'ai trouvé dans l'exemple suivant que la fonction était appelée à chaque fois que le composant est restitué par opposition au seul moment où il a été démonté du DOM, c'est-à-dire console.log("unmount");
chaque fois que le les composants sont rendus de nouveau.
Pourquoi donc?
function Something({ setShow }) {
const [array, setArray] = useState([]);
const myRef = useRef(null);
useEffect(() => {
const id = setInterval(() => {
setArray(array.concat("hello"));
}, 3000);
myRef.current = id;
return () => {
console.log("unmount");
clearInterval(myRef.current);
};
}, [array]);
const unmount = () => {
setShow(false);
};
return (
<div>
{array.map((item, index) => {
return (
<p key={index}>
{Array(index + 1)
.fill(item)
.join("")}
</p>
);
})}
<button onClick={() => unmount()}>close</button>
</div>
);
}
function App() {
const [show, setShow] = useState(true);
return show ? <Something setShow={setShow} /> : null;
}
Exemple en direct: https://codesandbox.io/s/vigilant-leavitt-z1jd2
En regardant le code, je pourrais deviner son en raison du deuxième paramètre [array]
. Vous le mettez à jour, il appellera donc un nouveau rendu. Essayez de définir un tableau vide.
Chaque mise à jour d'état appellera un nouveau rendu et un démontage, et ce tableau change.
Les documents React ont un section d'explication exactement à ce sujet.
En bref, la raison en est qu'une telle conception protège contre les données périmées et les bogues de mise à jour.
Le crochet useEffect
dans React est conçu pour gérer à la fois le rendu initial et tous les rendus suivants ( en savoir plus à ce sujet ).
Les effets sont contrôlés via leurs dépendances et non par le cycle de vie du composant qui les utilise.
À chaque fois que les dépendances d'un effet changent, useEffect
nettoiera l'effet précédent et exécutera le nouvel effet.
Une telle conception est plus prévisible - chaque rendu a son propre effet comportemental indépendant (pur) . Cela garantit que l'interface utilisateur affiche toujours les données correctes (car l'interface utilisateur dans le modèle mental de React est une capture d'écran de l'état pour un rendu particulier).
La façon dont nous contrôlons les effets passe par leurs dépendances.
Pour empêcher le nettoyage de s'exécuter sur chaque rendu, il suffit de ne pas modifier les dépendances de l'effet.
Dans votre cas concrètement, le nettoyage a lieu car array
est en train de changer, c'est-à-dire Object.is(oldArray, newArray) === false
useEffect(() => {
// ...
}, [array]);
// ^^^^^ you're changing the dependency of the effect
Vous provoquez ce changement avec la ligne suivante:
useEffect(() => {
const id = setInterval(() => {
setArray(array.concat("hello")); // <-- changing the array changes the effect dep
}, 3000);
myRef.current = id;
return () => {
clearInterval(myRef.current);
};
}, [array]); // <-- the array is the effect dep
Cela semble attendu. Selon la documentation ici, useAffects
est appelé après le premier rendu, chaque mise à jour et démontage.
https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects
Pointe
Si vous connaissez les méthodes de cycle de vie de la classe React, vous pouvez penser à useEffect Hook comme componentDidMount, componentDidUpdate et avant componentWillUnmount combinés.