web-dev-qa-db-fra.com

React hooks - bonne façon de supprimer les délais d'attente et les intervalles

Je ne comprends pas pourquoi, lorsque j'utilise setTimeout function, mon composant de réaction démarre dans le fichier console.log infini. Tout fonctionne, mais les ordinateurs commencent à prendre du retard. Certaines personnes disent que cette fonction modifie temporairement mon état et ce composant de ré-affichage, ce qui active le nouveau minuteur, etc. Maintenant, j'ai besoin de comprendre comment effacer c'est juste.

export default function Loading() {
  // if data fetching is slow, after 1 sec i will show some loading animation
  const [showLoading, setShowLoading] = useState(true)
  let timer1 = setTimeout(() => setShowLoading(true), 1000)

  console.log('this message will render  every second')
  return 1
}

Effacer dans une version différente du code ne contribuant pas à:

const [showLoading, setShowLoading] = useState(true)
  let timer1 = setTimeout(() => setShowLoading(true), 1000)
  useEffect(
    () => {
      return () => {
        clearTimeout(timer1)
      }
    },
    [showLoading]
  )
14
RTW

La fonction de retour dans useEffect s'exécute chaque fois que useEffect est exécuté (à l'exception de la première exécution lors du montage du composant). Pensez-y car chaque fois qu'il y a une nouvelle exécution useEffect, l'ancienne est supprimée.

C'est une manière efficace d'utiliser et d'effacer les délais ou les intervalles:

export default function Loading() {   
     const [showLoading, setShowLoading] = useState(false)

     useEffect(
        () => {
          let timer1 = setTimeout(() => setShowLoading(true), 1000)

          // this will clear Timeout when component unmont like in willComponentUnmount
          return () => {
            clearTimeout(timer1)
          }
        },
        [] //useEffect will run only one time
           //if you pass a value to array, like this [data] than clearTimeout will run every time this value changes (useEffect re-run)
      )

 return showLoading && <div>I will be visible after ~1000ms</div>
}

Si vous devez effacer des délais d'attente ou des intervalles quelque part à l'extérieur:

export default function Loading() {   
     const [showLoading, setShowLoading] = useState(false)

     const timerToClearSomewhere = useRef(false) //now you can pass timer to another component

     useEffect(
        () => {
          timerToClearSomewhere.current = setInterval(() => setShowLoading(true), 1000)

          return () => {
            clearInterval(timerToClearSomewhere.current)
          }
        },
        []
      )

  //here we can imitate clear from somewhere else place
  useEffect(() => {
    setTimeout(() => clearInterval(timerToClearSomewhere.current), 15000)
  }, [])

 return showLoading && <div>I will be visible after ~1000ms</div>
}

Si vous avez besoin de gérer la file d'attente (changement d'état dans timer/intervalle), cherchez ma réponse ici.

30
RTW

Votre ordinateur était à la traîne parce que vous avez probablement oublié de transmettre le tableau vide en tant que deuxième argument de useEffect et a déclenché un setState dans le rappel. Cela provoque une boucle infinie parce que useEffect est déclenché lors du rendu.

Voici un moyen efficace de définir une minuterie sur mount et de la supprimer lors du démontage:

function App() {
  React.useEffect(() => {
    const timer = window.setInterval(() => {
      console.log('1 second has passed');
    }, 1000);
    return () => { // Return callback to run on unmount.
      window.clearInterval(timer);
    };
  }, []); // Pass in empty array to run useEffect only on mount.

  return (
    <div>
      Timer Example
    </div>
  );
}

ReactDOM.render(
  <div>
    <App />
  </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>
4
Yangshun Tay