reduxjs / redux-toolkit

The official, opinionated, batteries-included toolset for efficient Redux development
https://redux-toolkit.js.org
MIT License
10.55k stars 1.13k forks source link

RTK Query: Stop/change polling time depending on query results #1651

Open alexiri opened 2 years ago

alexiri commented 2 years ago

I'm currently using hooks to query an API and set up a polling interval for it, like so:

const {
    data: event,
    isLoading,
    isSuccess,
    isError,
    error,
} = useGetEventQuery(eventId, {
    pollingInterval: 2000,
})

However, if the API returns a 404 not found, it doesn't make sense to continue polling every 2 seconds. Is there some way to stop polling on error? It would also be nice if I could change the polling interval depending on the results of the query, say to increase the polling time if the server took too long to respond. Is this at all possible?

Renaud009 commented 2 years ago

That would be awesome for stopping polling avec condition success or after n number of errors.

The error counter could be implement like this I guess but having it supported builtin in the future by an rtk-query options could be very much much better (UNTESTED CODE BELLOW):

const POLLING_INTERVAL = 5000;
const MAX_FOLLOWING_ERROR_COUNT = 5;

export const AnyContainer: FunctionComponent = () => {
  const errorCounterRef = useRef(0);
  const [isPollingActive, setIsPollingActive] = useState(true);
  const { data, error, isLoading } = useAnyQuery(
    {
      // query args
    },
    {
      pollingInterval: POLLING_INTERVAL,
      skip: !isPollingActive,
    },
  );
  const validData= data; // ... data selection

  if (isLoading) {
    return <LoadingPage />;
  }

  if (!validData|| error) {
    if (error) {
      errorCounterRef.current++;

      // Stop polling after MAX_FOLLOWING_ERROR_COUNT reached
      if (errorCounterRef.current > MAX_FOLLOWING_ERROR_COUNT) {
        setIsPollingActive(false);
      }
    }

    return null; // error component
  }

  // Reset counter on success
  errorCounterRef.current = 0;

  return <AnyComponent data={data} />;
};
alexiri commented 2 years ago

I'm not sure if I've done something wrong, but it looks like this doesn't work very well. When an error occurs (I have MAX_FOLLOWING_ERROR_COUNT=1) and setIsPollingActive(false) is executed, that triggers another query request, despite the value of isPollingActive. After this second request, error is undefined and isError is false, so I can no longer show the user what the error was.

Renaud009 commented 2 years ago

Yeah, I figured out some problems and weird behaviours with that code snippet that i didn't have the time to fix since I abandonned the polling featue. Feel free to post a better version if you have it fixed.

hoekma commented 2 years ago

I was able to turn the polling on/off by doing something like this:

  ...

  const [pollingInterval, setPollingInterval] = useState(3000);
  const {data} = myRTKQuery(someParameter, {pollingInterval});

  useEffect(() => {
     if (someCancelCondition){
         setPollingInterval(0);
     } else {
         setPollingInterval(3000);
     }
  }, [setPollingInterval, someCancelCondition]);

 ...
aeciolevy commented 4 months ago

@markerikson what is the proper way to stop RTK Query polling?

Could use the signal, and not rely on a useState to stop the polling?

markerikson commented 4 months ago

@aeciolevy sorry, afraid I don't understand the question. Can you clarify?

aeciolevy commented 4 months ago

Sorry @markerikson I did not give any context.

I saw here that the polling state is stoped by setting the polling time to 0

  const [pollingInterval, setPollingInterval] = useState(3000);
  const {data} = myRTKQuery(someParameter, {pollingInterval});

  useEffect(() => {
     if (someCancelCondition){
         setPollingInterval(0);
     } else {
         setPollingInterval(3000);
     }
  }, [setPollingInterval, someCancelCondition]);

And in this codesandbox: https://codesandbox.io/p/sandbox/rtk-query-multi-fetch-poll-r4m2r?file=%2Fsrc%2Fservices%2Fpokemon.ts

I was wondering if there is another way to stop polling without a useState.

Could we somehow access the AbortSignal defined on the baseQuery to abort in case we want to abort the polling request?

markerikson commented 4 months ago

Dropping in a related link with a similar request for polling configuration: https://www.kxlaa.com/articles/yes-i-would-use-redux-in-2024