web-dev-qa-db-fra.com

variable dans useState ne se met pas à jour dans callback useEffect

Je rencontre un problème lors de l'utilisation des crochets useState et useEffect

import { useState, useEffect } from "react";

const counter = ({ count, speed }) => {
    const [inc, setInc] = useState(0);

    useEffect(() => {

        const counterInterval = setInterval(() => {
            if(inc < count){
                setInc(inc + 1);
            }else{
                clearInterval(counterInterval);
            }
        }, speed);

    }, [count]);

    return inc;
}

export default counter;

Le code ci-dessus est un composant de compteur, il prend le compte en accessoires, puis initialise inc avec 0 et l'incrémente jusqu'à ce qu'il devienne égal au compte

Le problème est que je n'obtiens pas la valeur mise à jour de inc dans le rappel de useEffect et setInterval chaque fois que j'obtiens 0, donc cela rend inc comme 1 et setInterval n'est jamais clair. Je pense que inc doit être en fermeture d'utilisation callback useEffect et setInterval donc je dois y mettre la mise à jour inc, donc c'est peut-être un bug?

Je ne peux pas passer inc dans les dépendances (ce qui est suggéré dans d'autres questions similaires) car dans mon cas, j'ai définiInterval dans useEffect, donc passer inc dans le tableau de dépendances provoque une boucle infinie

J'ai une solution de travail utilisant un composant avec état, mais je veux y parvenir en utilisant un composant fonctionnel

7
Abhay Sehgal

Les principaux problèmes qui doivent être traités sont fermetures et l'intervalle de compensation sur une condition qui dépend des accessoires.

Vous devez ajouter la vérification conditionnelle dans la fonction setState:

setInc(inc => (inc < count ? inc + 1 : inc));

De plus, l'intervalle d'effacement doit se produire lors du démontage.

Si vous souhaitez ajouter clearInterval à condition (inc < count), vous devez enregistrer les références pour l'ID d'intervalle et le nombre accru:

import React, { useState, useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';

const useCounter = ({ count, speed }) => {
  const [inc, setInc] = useState(0);

  const incRef = useRef(inc);
  const idRef = useRef();

  useEffect(() => {
    idRef.current = setInterval(() => {
      setInc(inc => (inc < count ? inc + 1 : inc));
      incRef.current++;
    }, speed);

    return () => clearInterval(idRef.current);
  }, [count, speed]);

  useEffect(() => {
    if (incRef.current > count) {
      clearInterval(idRef.current);
    }
  }, [count]);

  useEffect(() => {
    console.log(incRef.current);
  });

  return inc;
};

const App = () => {
  const inc = useCounter({ count: 10, speed: 1000 });
  return <h1>Counter : {inc}</h1>;
};

ReactDOM.render(<App />, document.getElementById('root'));

Edit Q-59017467-DepCounter

0
Dennis Vash