412 votes

Comment utiliser le callback `setState` sur les react hooks ?

React hooks introduit useState pour définir l'état des composants. Mais comment puis-je utiliser les hooks pour remplacer le callback comme le code ci-dessous :

setState(
  { name: "Michael" },
  () => console.log(this.state)
);

Je veux faire quelque chose après la mise à jour de l'état.

Je sais que je peux utiliser useEffect pour faire les choses supplémentaires mais je dois vérifier l'état de la valeur précédente ce qui nécessite un peu de code. Je cherche une solution simple qui peut être utilisée avec le logiciel useState crochet.

2 votes

Dans la classe component, j'ai utilisé async et await pour obtenir le même résultat que ce que vous avez fait pour ajouter un callback dans setState. Malheureusement, cela ne fonctionne pas dans le hook. Même si j'ai ajouté async et await, react n'attend pas la mise à jour de l'état. Peut-être que useEffect est le seul moyen de le faire.

2 votes

@Zhao, vous n'avez pas encore marqué la bonne réponse. Pouvez-vous gentiment nous accorder quelques secondes

1voto

arjun sah Points 355

Laissez-moi vous dire que useEffect est exécuté une fois par défaut et qu'à chaque fois, le tableau des dépendances change.

Vérifiez l'exemple ci-dessous : :

import React,{ useEffect, useState } from "react";

const App = () => {
  const [age, setAge] = useState(0);
  const [ageFlag, setAgeFlag] = useState(false);

  const updateAge = ()=>{
    setAgeFlag(false);
    setAge(age+1);
    setAgeFlag(true);
  };

  useEffect(() => {
    if(!ageFlag){
      console.log('effect called without change - by default');
    }
    else{
      console.log('effect called with change ');
    }
  }, [ageFlag,age]);

  return (
    <form>
      <h2>hooks demo effect.....</h2>
      {age}
      <button onClick={updateAge}>Text</button>
    </form>
  );
}

export default App;

Si vous voulez que le callback setState soit exécuté avec les hooks, utilisez la variable flag et donnez un bloc IF ELSE OR IF à l'intérieur de useEffect de sorte que lorsque les conditions sont satisfaites, seul ce bloc de code s'exécute. Quel que soit le nombre de fois où l'effet s'exécute, le tableau des dépendances change, mais le code IF à l'intérieur de l'effet ne s'exécutera qu'en fonction de ces conditions spécifiques.

1voto

Oliver Joseph Ash Points 571

Nous pouvons écrire un hook appelé useScheduleNextRenderCallback qui renvoie une fonction "schedule". Après avoir appelé setState nous pouvons appeler la fonction "schedule", en passant un callback que nous voulons exécuter lors du prochain rendu.

import { useCallback, useEffect, useRef } from "react";

type ScheduledCallback = () => void;
export const useScheduleNextRenderCallback = () => {
  const ref = useRef<ScheduledCallback>();

  useEffect(() => {
    if (ref.current !== undefined) {
      ref.current();
      ref.current = undefined;
    }
  });

  const schedule = useCallback((fn: ScheduledCallback) => {
    ref.current = fn;
  }, []);

  return schedule;
};

Exemple d'utilisation :

const App = () => {
  const scheduleNextRenderCallback = useScheduleNextRenderCallback();

  const [state, setState] = useState(0);

  const onClick = useCallback(() => {
    setState(state => state + 1);
    scheduleNextRenderCallback(() => {
      console.log("next render");
    });
  }, []);

  return <button onClick={onClick}>click me to update state</button>;
};

Cas de test réduit : https://stackblitz.com/edit/react-ts-rjd9jk

0voto

SiroSong Points 1

Je ne pense pas que distinguer monté ou non avec useRef soit un bon moyen, n'est-ce pas un meilleur moyen en déterminant la valeur générée useState() dans useEffect() si c'est la valeur initiale ?

const [val, setVal] = useState(null)

useEffect(() => {
  if (val === null) return
  console.log('not mounted, val updated', val)
}, [val])

0voto

Priyanshu Chauhan Points 2141

La réponse acceptée n'a pas fonctionné pour moi, si j'avais beaucoup de traitement à faire. Le fait de placer la logique dans la boucle d'événement (setTimeout) résout les problèmes.

Dans l'exemple ci-dessous, je fixe une variable de chargeur avant de faire un traitement lourd.

    const [counter, setCounter] = useState(0);
    const [showLoader, setShowLoader] = useState(false);

    const doSomething = () => {
      setLoader(true);
      setTimeout(() => {
        // do lot of data processing
        setCounter(123);
      })
    }

      useEffect(() => {
        setLoader(false)
      }, [setLoader, setCounter]);

0voto

Tyler Chong Points 39

Jusqu'à ce que nous disposions d'un support natif intégré pour le callback setState, nous pouvons utiliser la méthode javascript classique ... appeler la fonction et lui passer directement les nouvelles variables.

  const [counter, setCounter] = useState(0);

  const doSomething = () => {
    const newCounter = 123
    setCounter(newCounter);
    doSomethingWCounter(newCounter);
  };

  function doSomethingWCounter(newCounter) {
    console.log(newCounter); // 123
  }

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