web-dev-qa-db-fra.com

React Crochets et équivalent du cycle de vie des composants

Quels sont les équivalents des hooks de cycle de vie componentDidMount, componentDidUpdate et componentWillUnmount en utilisant React hooks comme useEffect?

18
Yangshun Tay

componentDidMount

Passez un tableau vide comme deuxième argument à useEffect() pour exécuter uniquement le rappel sur le montage uniquement.

function ComponentDidMount() {
  const [count, setCount] = React.useState(0);
  React.useEffect(() => {
    console.log('componentDidMount');
  }, []);

  return (
    <div>
      <p>componentDidMount: {count} times</p>
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        Click Me
      </button>
    </div>
  );
}

ReactDOM.render(
  <div>
    <ComponentDidMount />
  </div>,
  document.querySelector("#app")
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>

componentDidUpdate

componentDidUpdate() est invoquée immédiatement après la mise à jour. Cette méthode n'est pas appelée pour le rendu initial. useEffect s'exécute sur chaque rendu, y compris le premier. Donc, si vous voulez avoir un équivalent strict comme componentDidUpdate, vous devez utiliser useRef pour déterminer si le composant a été monté une fois. Si vous voulez être encore plus strict, utilisez useLayoutEffect(), mais il se déclenche de manière synchrone. Dans la plupart des cas, useEffect() devrait être suffisant.

Cette la réponse est inspirée par Tholle , tout le mérite lui revient.

function ComponentDidUpdate() {
  const [count, setCount] = React.useState(0);

  const isFirstUpdate = React.useRef(true);
  React.useEffect(() => {
    if (isFirstUpdate.current) {
      isFirstUpdate.current = false;
      return;
    }

    console.log('componentDidUpdate');
  });

  return (
    <div>
      <p>componentDidUpdate: {count} times</p>
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        Click Me
      </button>
    </div>
  );
}

ReactDOM.render(
  <ComponentDidUpdate />,
  document.getElementById("app")
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>

componentWillUnmount

Renvoie un rappel dans l'argument de rappel useEffect et il sera appelé avant le démontage.

function ComponentWillUnmount() {
  function ComponentWillUnmountInner(props) {
    React.useEffect(() => {
      return () => {
        console.log('componentWillUnmount');
      };
    }, []);

    return (
      <div>
        <p>componentWillUnmount</p>
      </div>
    );
  }
  
  const [count, setCount] = React.useState(0);

  return (
    <div>
      {count % 2 === 0 ? (
        <ComponentWillUnmountInner count={count} />
      ) : (
        <p>No component</p>
      )}
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        Click Me
      </button>
    </div>
  );
}

ReactDOM.render(
  <div>
    <ComponentWillUnmount />
  </div>,
  document.querySelector("#app")
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>
37
Yangshun Tay

De React docs :

Si vous connaissez les méthodes de cycle de vie de la classe React, vous pouvez penser à useEffect Hook comme componentDidMount, componentDidUpdate et componentWillUnmount combinés.

Par ce dicton, ils veulent dire:

componentDidMount est une sorte de useEffect(callback, [])

componentDidUpdate est en quelque sorte useEffect(callback, [dep1, dep2, ...]) - le tableau de dep indique à React: "si l'un des deps est changé, lancez le rappel après avoir rendu ".

componentDidMount + componentDidUpdate est une sorte de useEffect(callback)

componentWillUnmount est en quelque sorte la fonction retournée par le rappel:

useEffect(() => { 
    /* some code */
    return () => { 
      /* some code to run when rerender or unmount */
    }
)

Avec l'aide de Dan Abramov la formulation de son blog , et quelques ajouts de ma part:

Bien que vous puissiez utiliser ces crochets, ce n'est pas un équivalent exact. Contrairement à componentDidMount et componentDidUpdate, il capturera les accessoires et l'état. Ainsi, même à l'intérieur des rappels, vous verrez les accessoires et l'état du rendu spécifique (ce qui signifie dans componentDidMount les accessoires et l'état initiaux). Si vous voulez voir quelque chose de "plus récent", vous pouvez l'écrire dans une référence. Mais il existe généralement un moyen plus simple de structurer le code afin que vous n'ayez pas à le faire. La fonction retournée qui suppose être une alternative à componentWillUnmount n'est pas non plus un équivalent exact, car la fonction s'exécutera à chaque fois que le composant sera rendu de nouveau et lorsque le composant sera démonté. Gardez à l'esprit que le modèle mental des effets est différent des cycles de vie des composants, et essayer de trouver leurs équivalents exacts peut vous confondre plus que vous aider. Pour devenir productif, vous devez "penser aux effets", et leur modèle mental est plus proche de la mise en œuvre de la synchronisation que de la réponse aux événements du cycle de vie.

Exemple tiré du blog de Dan:

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setTimeout(() => {
      console.log(`You clicked ${count} times`);
    }, 3000);
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

enter image description here

Si nous utilisons l'implémentation de classe:

componentDidUpdate() {
  setTimeout(() => {
    console.log(`You clicked ${this.state.count} times`);
  }, 3000);
}

enter image description here

this.state.count pointe toujours sur le dernier décompte plutôt que celui appartenant à un rendu particulier.

6
Edan Chetrit