0
votes

Empêcher les rendus infinis lors de la mise à jour de la variable d'état dans le hook useEffect avec les données récupérées à l'aide de useQuery de graphql

Graphql fournit le hook useQuery pour récupérer des données. Il sera appelé à chaque nouveau rendu du composant.

  const [stateOfValue, setStateOfValue] = useState({
    name: "jack",
    options: []
  });

  const someOperation = (currentState) => {
    return {
        ...currentState,
        options: [1, 2, 3]
      };
  }
  useEffect(() => {
    if (data) {
      let newValue = someOperation(stateOfValue);
      setStateOfValue(newValue);
    }
  }, [data, stateOfValue]);

J'utilise le hook useEffect pour contrôler le nombre de fois où "useQuery" doit être appelé.

Ce que je veux faire, c'est chaque fois que je reçois les données de useQuery, je veux effectuer une opération sur les données et la définir sur une autre variable d'état " stateOfValue " qui est une donnée d'objet imbriquée. Cela doit donc être fait à l'intérieur du hook useEffect.

Par conséquent, je dois ajouter mon stateOfValue et " data " (ceci a mes données API) variable en tant que dépendances au hook useEffect.

//mocking useQuery hook of graphql, which updates the data variable
  const data = useQuery(false);

En gros, j'ajoute toutes les variables qui sont utilisées dans mon useEffect en tant que dépendance car c'est la bonne façon de faire selon Dan Abramov. a >

Maintenant, selon react, les mises à jour d'état doivent être effectuées sans mutations pour que je crée un nouvel objet à chaque fois que j'ai besoin de mettre à jour l'état. Mais avec la définition d'un nouvel objet de variable d'état, mon composant est re-rendu, provoquant un rendu infini.

Comment procéder pour l'implémenter de telle manière que je passe toutes les variables à mon tableau de dépendances de useEffect, et en le faisant exécuter useEffect une seule fois.

Remarque: cela fonctionne si je n'ajoute pas la variable stateOfValue aux dépendances, mais cela mentir pour réagir.

Voici le lien reproduit.


1 commentaires

Ne pas ajouter stateOfValue aux dépendances peut ne pas mentir pour réagir - vous ne l'utilisez pas dans useEffect donc ce n'est pas réellement une dépendance et l'omettre est très bien


3 Réponses :


2
votes

Je pense que vous avez mal compris ce que vous voulez être dans le tableau des dépendances est [data, setStateOfValue] et non [data, stateOfValue] . parce que vous utilisez setStateOfValue et non stateOfValue dans useEffect Le bon est:

const [stateOfValue, setStateOfValue] = useState({
    name: "jack",
    options: []
  });

  const someOperation = useCallback((prevValue) => {
    return {
        ...prevValue,
        options: [1, 2, 3]
      };
  },[])
  useEffect(() => {
    if (data) {
      setStateOfValue(prevValue => {
        let newValue = someOperation(prevValue);
        return newValue
      });
    }
  }, [data, setStateOfValue,someOperation]);


2 commentaires

non, l'effet a une dépendance sur une opération qui provoquera un rendu infini ou une fermeture périmée


Cela résout l'exemple absurde de la question, mais je suppose qu'une fois terminé, cela fonctionnera mieux pour copier les données graphql dans l'état local. Également; ne créez pas d'extrait de code si vous ne pouvez pas l'exécuter.



1
votes

Tout d'abord, je vous demanderais si vous avez besoin de stocker stateOfValue comme état. Sinon (par exemple, il ne sera modifié par rien d'autre), vous pourriez potentiellement utiliser le hook useMemo à la place de

const data = useQuery(query, {
  onCompleted: response => {
    let newValue = someOperation();
    setStateOfValue(newValue);
  }
)

Maintenant, myComputedValue sera être le résultat de someOperation , mais il ne sera réexécuté que lorsque les données changeront

S'il est nécessaire de le stocker en tant qu'état, vous pourrez peut-être utiliser le onCompleted option dans useQuery

const myComputedValue = useMemo(() => someOperation(data), [data]);


0 commentaires

2
votes

Si vous voulez définir l'état d'un effet, vous pouvez faire ce qui suit:

const data = useQuery(query);
const [stateOfValue, setStateOfValue] = useState({});
const someOperation = useCallback(
  () =>
    setStateOfValue((current) => ({ ...current, data })),
  [data]
);
useEffect(() => someOperation(), [someOperation]);

À chaque fois que les données changent, la fonction SomeOperation est recréée et provoque l'exécution de l'effet. À un moment donné, les données sont chargées ou il y a une erreur et les données ne sont pas recréées, ce qui empêche la création d'une opération et l'effet ne s'exécute pas à nouveau.


0 commentaires