vercel / swr

React Hooks for Data Fetching
https://swr.vercel.app
MIT License
30.53k stars 1.22k forks source link

ReactStrictMode with Axios abortController makes my request canceled #2783

Open batgos opened 1 year ago

batgos commented 1 year ago

Bug report

Description / Observed Behavior

I created a wrapper of useSWR hook to handle abortion on request when my component gets unmounted. When I'm using my custom hook with the ReactStrictMode on, it just directly cancels my request. My custom hook doesn't re-fetch again after the first abortion or it shouldn't abort it to be able to make the request.

It's working perfectly if ReactStrictMode is off as my custom hook doesn't get unmount at first

Expected Behavior

I expect to see:

fetching
aborting
fetching

Or avoid the abortion, in the same way as if ReactStrictMode is off

fetching

Repro Steps / Code Example

I'm using my custom hook like this :

const request = useRequest({
    url: '/api/invitations',
    method: 'get',
  });

My useRequest code :

const useRequest = (request: AxiosRequestConfig | null): RequestType => {
  const abort_controller = new AbortController();

  const fetcher = async (
    requestFetcher: AxiosRequestConfig | null
  ): Promise<unknown> => {
      console.log('Fetch request');

    return await axios({
      ...requestFetcher,
      signal: abort_controller.signal,
    })
      .then((response) => {
        return response;
      });
  };

  const {
    data: dataSWR,
    isLoading,
    error
  } = useSWR(
    request && request.method === 'get' ? request.url : null,
    () => fetcher(request),
    {
      revalidateOnFocus: false,
      shouldRetryOnError: false,
    }
  );

  useEffect(() => {
  if (request !== null) {
      console.log('useEffect request');
    }
    return () => {
      if (request !== null) {
         console.log('Abort request');
        abort_controller.abort();
      }
    };
  }, []);

  return {
    loading: isLoading,
    status: dataSWR ? dataSWR?.status : 0,
    headers: dataSWR ? dataSWR?.headers : null,
    data: dataSWR ? dataSWR?.data.result : null,
    error: error,
  };
};

If I run it, It's printing :

useRequest.ts:22 Fetch request
useRequest.ts:49 useEffect request
useRequest.ts:53 Abort request
useRequest.ts:49 useEffect request

Additional Context

SWR: 2.0.3

WagnerMoreira commented 1 year ago

@batgos This is the intended behavior of React strict mode, check this page https://react.dev/reference/react/StrictMode#:~:text=development%2Donly%20behaviors%3A-,Your%20components%20will%20re%2Drender%20an%20extra%20time%20to%20find%20bugs%20caused%20by%20impure%20rendering.,-Your%20components%20will

It is not related to SWR

batgos commented 1 year ago

@WagnerMoreira Yes I know but I'm wondering how SWR is supposed to work with React strict mode as the request gets aborted firstly cause of the unmount and then not re-fetch at the second render

WagnerMoreira commented 1 year ago

@batgos I think SWR is unaware of this, as the abort and the request are performed by Axios. So it would be up to making your abort logic based on config or something of that nature if you want to be able to abort on unmount but not have that always happening

batgos commented 1 year ago

@WagnerMoreira If it's just Axios and aborts logic, I can manage it, but when Axios is used with SWR, the logic changes. That's why I'm wondering if there is specific behavior with SWR about abortion.