2 votes

Comment utiliser correctement useEffect pour un appel asynchrone de récupération avec react ? react-hooks/exhaustive-deps

Bonjour, je rencontre un problème avec le useEffect dans React. Le code ci-dessous fonctionne comme il le devrait, mais es-lint suggère que je dois fournir les dépendances dans le tableau de dépendances de l'élément useEffect .

Code de travail avec // eslint-disable-next-line react-hooks/exhaustive-deps

export default function UsersList() {
   const [users, setUsers] = useState<User[]>([]);

   const { setError } = useContext(errorContext);
   const { isLoading, setIsLoading } = useContext(globalContext);

   useEffect(() => {
       if (users.length < 1) {
         fetchUsers();
       }
       // eslint-disable-next-line react-hooks/exhaustive-deps
     }, []);

     async function fetchUsers () {
       try {
         setIsLoading(true);
         const fetchedUsers = await api.getUsers();
         setUsers(fetchedUsers);
       } catch (error) {
         setError(error);
       } finally {
         setIsLoading(false);
       }
     }
}

Code de bouclage infini

J'ai essayé de l'écrire comme ça, mais le code déclenche une boucle infinie (parce que les états changent constamment dans la fonction et déclenchent la boucle infinie). useEffect à chaque fois à cause des dépendances déclarées)

 useEffect(() => {
    async function fetchUsers () {
      try {
        setIsLoading(true);
        const fetchedUsers = await api.getUsers();
        setUsers(fetchedUsers);
      } catch (error) {
        setError(error);
      } finally {
        setIsLoading(false);
      }
    }

    if (users.length < 1) {
      fetchUsers();
    }
  }, [setIsLoading, setError, users]);

J'ai également essayé de mettre le fetchUsers() dans le tableau des dépendances, mais cela n'a eu aucun effet.

Comment puis-je configurer correctement un appel asynchrone lors du montage du composant sans avoir à utiliser la fonction // eslint-disable-next-line react-hooks/exhaustive-deps ?

2voto

brmk Points 65

Votre fetchUsers se recrée avec chaque rendu déclenchant l'effet d'utilisation. Vous devez conserver la même référence d'un rendu à l'autre en l'entourant de useCallback voir https://reactjs.org/docs/hooks-reference.html#usecallback

De plus, pour s'assurer que nous n'appelons ce useEffect qu'une seule fois (lorsque le premier rendu se produit), nous pouvons utiliser useRef pour stocker une valeur booléenne qui empêchera le useEffect de tourner en boucle infinie

export default function UsersList() {
  const [users, setUsers] = useState<User[]>([]);

  const { setError } = useContext(errorContext);
  const { isLoading, setIsLoading } = useContext(globalContext);

  const fetchUsers = useCallback(async function () {
    try {
      setIsLoading(true);
      const fetchedUsers = await api.getUsers();
      setUsers(fetchedUsers);
    } catch (error) {
      setError(error);
    } finally {
      setIsLoading(false);
    }
  }, [setIsLoading, setUsers, setError]);

  // Added a ref here to ensure that we call this function only once in initial render
  // If you need to refetch the users on error, just call fetchUsers
  const isFetchedRef = useRef(false);
  useEffect(() => {
    if (!isFetchedRef.current) {
      isFetchedRef.current = true;
      fetchUsers();
    }
  }, [isLoading, fetchUsers]);
}

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