104 votes

React hooks useEffect uniquement lors de la mise à jour?

Si nous voulons restreindre useEffect à ne fonctionner que lorsque le composant est monté, nous pouvons ajouter un deuxième paramètre de useEffect avec [] .

 useEffect(() => {
  // ...
}, []);

Mais comment faire fonctionner useEffect uniquement au moment où le composant est mis à jour sauf le montage initial?

213voto

Shubham Khatri Points 67350

Si vous souhaitez que useEffect ne s'exécute que sur les mises à jour sauf le montage initial, vous pouvez utiliser useRef pour garder une trace de initialMount avec useEffect sans le deuxième paramètre.

 const isInitialMount = useRef(true);

useEffect(() => {
  if (isInitialMount.current) {
     isInitialMount.current = false;
  } else {
      // Your useEffect code here to be run on update
  }
});

46voto

Mario Campa Points 540

J'aime vraiment la réponse de Shubham, alors j'en ai fait un crochet personnalisé

 /**
 * A custom useEffect hook that only triggers on updates, not on initial mount
 * Idea stolen from: https://stackoverflow.com/a/55075818/1526448
 * @param {Function} effect
 * @param {Array<any>} dependencies
 */
export default function useUpdateEffect(effect, dependencies = []) {
  const isInitialMount = useRef(true);

  useEffect(() => {
    if (isInitialMount.current) {
      isInitialMount.current = false;
    } else {
      effect();
    }
  }, dependencies);
}

10voto

Sankalp Lakhina Points 73

Shubham et Mario suggèrent tous deux la bonne approche, mais le code est encore incomplet et ne prend pas en compte les cas suivants.

  1. Si le composant se démonte, il devrait réinitialiser son indicateur
  2. La fonction effect qui passe peut avoir une fonction de nettoyage renvoyée, qui ne sera jamais appelée

Partage ci-dessous un code plus complet qui couvre ci-dessus deux cas manquants:

 import React from 'react';

const useIsMounted = function useIsMounted() {
  const isMounted = React.useRef(false);

  React.useEffect(function setIsMounted() {
    isMounted.current = true;

    return function cleanupSetIsMounted() {
      isMounted.current = false;
    };
  }, []);

  return isMounted;
};

const useUpdateEffect = function useUpdateEffect(effect, dependencies) {
  const isMounted = useIsMounted();
  const isInitialMount = React.useRef(true);

  React.useEffect(() => {
    let effectCleanupFunc = function noop() {};

    if (isInitialMount.current) {
      isInitialMount.current = false;
    } else {
      effectCleanupFunc = effect() || effectCleanupFunc;
    }
    return () => {
      effectCleanupFunc();
      if (!isMounted.current) {
        isInitialMount.current = true;
      }
    };
  }, dependencies); // eslint-disable-line react-hooks/exhaustive-deps
};

5voto

awongh Points 469

Vous pouvez le contourner en définissant l'état sur une valeur initiale non booléenne (comme une valeur nulle):

   const [isCartOpen,setCartOpen] = useState(null);
  const [checkout,setCheckout] = useState({});

  useEffect(() => {

    // check to see if its the initial state
    if( isCartOpen === null ){

      // first load, set cart to real initial state, after load
      setCartOpen( false );
    }else if(isCartOpen === false){

      // normal on update callback logic
      setCartOpen( true );
    }
  }, [checkout]);

-3voto

Ahmad Libda Points 21

Utilisez la fonction Cleanup du useEffect sans utiliser un tableau vide comme second paramètre:

 useEffect(() => { 
  return () => {
  // your code to be run on update only.
  }
});

Vous pouvez utiliser un autre useEffect (avec un tableau vide comme deuxième paramètre) pour le montage initial, où vous placez votre code dans sa fonction principale.

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