web-dev-qa-db-fra.com

réactifs hooks useEffect () nettoyage pour seulement componentWillUnmount?

Permettez-moi d'expliquer le résultat de ce code pour poser mon problème facilement.

const ForExample = () => {
    const [name, setName] = useState('');
    const [username, setUsername] = useState('');

    useEffect(() => {
        console.log('effect');
        console.log({
            name,
            username
        });

        return () => {
            console.log('cleaned up');
            console.log({
                name,
                username
            });
        };
    }, [username]);

    const handleName = e => {
        const { value } = e.target;

        setName(value);
    };

    const handleUsername = e => {
        const { value } = e.target;

        setUsername(value);
    };

    return (
        <div>
            <div>
                <input value={name} onChange={handleName} />
                <input value={username} onChange={handleUsername} />
            </div>
            <div>
                <div>
                    <span>{name}</span>
                </div>
                <div>
                    <span>{username}</span>
                </div>
            </div>
        </div>
    );
};

Lorsque ForExample component Monte, "effet" sera enregistré. Ceci est lié à la componentDidMount().

Et chaque fois que je modifie la saisie du nom, "effet" et "nettoyé" seront enregistrés. Inversement, aucun message ne sera enregistré chaque fois que je changerai le nom d'utilisateur car j'ai ajouté [username] Au deuxième paramètre de useEffect(). Ceci est lié à la componentDidUpdate()

Enfin, lorsque ForExample component Sera démonté, "nettoyé" sera enregistré. Ceci est lié à la componentWillUnmount().

Nous savons tous que.

Pour résumer, "nettoyé" est invoqué chaque fois que le composant est restitué (inclut le démontage)

Si je veux que ce composant se connecte "nettoyé" uniquement pour le moment où il est démonté, je dois simplement changer le deuxième paramètre de useEffect() en [].

Mais si je change [username] En [], ForExample component N'implémente plus la componentDidUpdate() pour la saisie du nom.

Ce que je veux faire, c'est que, pour que le composant prenne en charge à la fois componentDidUpdate() uniquement pour la saisie de nom et componentWillUnmount(). (enregistrement "nettoyé" uniquement pour le moment où le composant est démonté)

45
koo

Étant donné que le nettoyage ne dépend pas du username, vous pouvez placer le nettoyage dans un useEffect distinct auquel est attribué un tableau vide comme deuxième argument.

Exemple

const { useState, useEffect } = React;

const ForExample = () => {
  const [name, setName] = useState("");
  const [username, setUsername] = useState("");

  useEffect(
    () => {
      console.log("effect");
    },
    [username]
  );

  useEffect(() => {
    return () => {
      console.log("cleaned up");
    };
  }, []);

  const handleName = e => {
    const { value } = e.target;

    setName(value);
  };

  const handleUsername = e => {
    const { value } = e.target;

    setUsername(value);
  };

  return (
    <div>
      <div>
        <input value={name} onChange={handleName} />
        <input value={username} onChange={handleUsername} />
      </div>
      <div>
        <div>
          <span>{name}</span>
        </div>
        <div>
          <span>{username}</span>
        </div>
      </div>
    </div>
  );
};

function App() {
  const [shouldRender, setShouldRender] = useState(true);

  useEffect(() => {
    setTimeout(() => {
      setShouldRender(false);
    }, 5000);
  }, []);

  return shouldRender ? <ForExample /> : null;
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>
42
Tholle

vous pouvez utiliser plus d'une utilisation

par exemple, si ma variable est data1, je peux utiliser tout cela dans mon composant

useEffect( () => console.log("mount"), [] );
useEffect( () => console.log("will update data1"), [ data1 ] );
useEffect( () => console.log("will update any") );
useEffect( () => () => console.log("will update data1 or unmount"), [ data1 ] );
useEffect( () => () => console.log("unmount"), [] );
56
Mehran Motiee
function LegoComponent() {

  const [lego, setLegos] = React.useState([])

  React.useEffect(() => {
    let isSubscribed = true
    fetchLegos().then( legos=> {
      if (isSubscribed) {
        setLegos(legos)
      }
    })
    return () => isSubscribed = false
  }, []);

  return (
    <ul>
    {legos.map(lego=> <li>{lego}</li>)}
    </ul>
  )
}

Dans le code ci-dessus, la fonction fetchLegos renvoie une promesse. Nous pouvons "annuler" la promesse en ayant un conditionnel dans la portée de useEffect, empêchant l'application de définir l'état après le démontage du composant.

Avertissement: impossible d'effectuer une mise à jour d'état React sur un composant non monté. Il s'agit d'un no-op, mais il indique une fuite de mémoire dans votre application. Pour corriger, annulez tous les abonnements et tâches asynchrones dans une fonction de nettoyage useEffect.

0
Daniel Yap