Amir-Mousavi
Amir-Mousavi

Reputation: 4563

react useEffect hook infinite loop caused by axios cancel token [react-hooks/exhaustive-deps]

In my react component I am using useEffect to fetch data on the mount of component and each time that filters change. Everything works as it should but react-hooks/exhaustive-deps throws warning that the fetcher function should be in the array of dependencies. By adding fetcher to dependencies list the app gets into an infinite loop. The fetcher receives a new Axios cancel token on each run which causes an infinite loop of calls to fetcher. How should I handle this situation, without disabling the rule?

he fetcher function is outside of the useEffect, cause another callback functions (passed to children) might call the fetcher. e.g. a modal that can edit user and on successful editing calls fetcher to reload new users

const [isLoading, setIsLoading] = React.useState<boolean>(false);
const [users, setUsers] = React.useState<IUser[]>([]);
const [filters, setFilters] = React.useState<ITableFilters>({...initFilters});

const fetcher = async (s: CancelTokenSource): Promise<void> => {
    setIsLoading(true);
    const params = { ...filters };
    try {
      const { data} = await fetchAllUsers({
        params,
        cancelToken: s.token
      });
      setUsers(data.users);
      setIsLoading(false);
    } catch (error) {
      handleResponseError(error);// wchich checks axios.isCancel
      setIsLoading(false);
    }
}

  React.useEffect(() => {
    const source = axios.CancelToken.source();
    // tslint:disable-next-line: no-floating-promises
    fetcher(source);
    return function cleanup() {
      source.cancel();
    };
  }, [filters]);

Upvotes: 0

Views: 601

Answers (1)

Philip Feldmann
Philip Feldmann

Reputation: 8405

You could use useCallback, therefore the reference to the fetcher should stay the same, not causing any more re-renders.

const fetcher = useCallback(async (s: CancelTokenSource) => {
  setIsLoading(true);
  const params = { ...filters };
  try {
    const { data} = await fetchAllUsers({
      params,
      cancelToken: s.token
    });
    setUsers(data.users);
    setIsLoading(false);
  } catch (error) {
    handleResponseError(error);// wchich checks axios.isCancel
    setIsLoading(false);
  }
}, [setIsLoading, setUsers, filters])

Upvotes: 1

Related Questions