134 votes

Avec useEffect, comment puis-je éviter d'appliquer un effet lors du rendu initial ?

Avec les nouveaux crochets d'effet de React, je peux dire à React de ne pas appliquer un effet si certaines valeurs n'ont pas changé entre deux présentations - Exemple tiré de la documentation de React :

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes

Mais l'exemple ci-dessus applique l'effet sur le rendu initial, et sur les rendus ultérieurs où count a changé. Comment puis-je dire à React d'ignorer l'effet lors du rendu initial ?

2 votes

Avez-vous regardé dans React.useMemo ?

6voto

cYee Points 658

Laissez-moi vous présenter react-use .

Je veux courir seulement après le premier rendu ? useUpdateEffect

Je veux courir une seule fois ? useEffectOnce

Vous voulez savoir est-ce la première monture ? useFirstMountState

Wanna comparaison approfondie , comparaison superficielle ou papillon des gaz effet ? Beaucoup plus .

Vous ne voulez pas installer une bibliothèque ? Vérifiez le code & copie. (peut-être un star pour les bonnes gens là-bas aussi)

1 votes

On dirait que c'est un très bon paquet

4voto

NearHuscarl Points 492

Voici mon implémentation basée sur celle d'Estus Flask réponse écrit en Typescript. Il supporte également le callback de nettoyage.

import { DependencyList, EffectCallback, useEffect, useRef } from 'react';

export function useDidUpdateEffect(
  effect: EffectCallback,
  deps?: DependencyList
) {
  // a flag to check if the component did mount (first render's passed)
  // it's unrelated to the rendering process so we don't useState here
  const didMountRef = useRef(false);

  // effect callback runs when the dependency array changes, it also runs
  // after the component mounted for the first time.
  useEffect(() => {
    // if so, mark the component as mounted and skip the first effect call
    if (!didMountRef.current) {
      didMountRef.current = true;
    } else {
      // subsequent useEffect callback invocations will execute the effect as normal
      return effect();
    }
  }, deps);
}

Démonstration en direct

La démonstration en direct ci-dessous montre la différence entre useEffect et useDidUpdateEffect crochets

Edit 53179075/with-useeffect-how-can-i-skip-applying-an-effect-upon-the-initial-render

1voto

rahulxyz Points 361

La solution ci-dessous est similaire à la précédente, mais elle est un peu plus propre que celle que je préfère.

const [isMount, setIsMount] = useState(true);
useEffect(()=>{
        if(isMount){
            setIsMount(false);
            return;
        }

        //Do anything here for 2nd render onwards
}, [args])

2 votes

Ce n'est pas une façon idéale de procéder, car la définition de l'état provoque un autre rendu.

1voto

Shiraz Points 380

J'allais commenter la réponse actuellement acceptée, mais je n'ai plus de place !

Tout d'abord, il est important de ne plus penser en termes d'événements du cycle de vie lors de l'utilisation de composants fonctionnels. Pensez en termes de changements de propriétés/états. J'ai eu une situation similaire où je voulais seulement qu'un composant particulier useEffect à déclencher lorsqu'un accessoire particulier ( parentValue dans mon cas) change par rapport à son état initial. J'ai donc créé une référence basée sur sa valeur initiale :

const parentValueRef = useRef(parentValue);

et a ensuite inclus le texte suivant au début de l'article. useEffect fn :

if (parentValue === parentValueRef.current) return;
parentValueRef.current = parentValue;

(Fondamentalement, n'exécutez pas l'effet si parentValue n'a pas changé. Mettez à jour la référence si elle a changé, prête pour la prochaine vérification, et continuez à exécuter l'effet).

Ainsi, bien que d'autres solutions proposées puissent résoudre le cas d'utilisation particulier que vous avez fourni, il sera utile à long terme de changer votre façon de penser par rapport aux composants fonctionnels.

Considérez qu'il s'agit principalement de rendre un composant en fonction de certains accessoires.

Si vous avez vraiment besoin d'un état local, alors useState fournira cela, mais ne supposez votre problème sera résolu en stockant l'état local.

Si vous disposez d'un code qui modifie vos accessoires pendant le rendu, cet "effet secondaire" doit être enveloppé dans une balise useEffect mais le but est d'avoir un rendu propre qui n'est pas affecté par quelque chose qui change pendant le rendu. Le site useEffect sera exécuté après que le rendu soit terminé et, comme vous l'avez souligné, il est exécuté à chaque rendu - à moins que le second paramètre ne soit utilisé pour fournir une liste de props/states afin d'identifier les éléments modifiés qui feront qu'il sera exécuté plusieurs fois.

Bonne chance dans votre voyage vers les composants fonctionnels / crochets ! Il est parfois nécessaire de désapprendre quelque chose pour s'approprier une nouvelle façon de faire les choses :) Ce document est une excellente introduction : https://overreacted.io/a-complete-guide-to-useeffect/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X