Skip to content

Polling continues after component dismount #5121

@MatthewRorke

Description

@MatthewRorke

Hello,

Summary
I have a standard shared endpoint setup and use the injectEndpoint for configuring my endpoints and sorting them into neat directories.

Problem
When polling an endpoint via RTK Query. The endpoint will still poll (one last time) after the component has unmounted.

Example

  • I have a small application with two primary paths, using react-router.
  • The <Session /> component will run a "heartbeat" query every 30 seconds. Additionally, I have attached two timers to ensure that the component successfully dismounts.
  • When I change path to a route that is under <Public /> and not <Session /> the polling time will still continue to run one last time, triggering the endpoint while on the wrong component causing unexpected state changes.

The endpoint:

import api from 'api'; // Aliased
import apiTags from './apiTags';

const globalSettingsApi = api.injectEndpoints({
  endpoints: builder => ({
    getHeartbeat: builder.query({
      query: () => `heartbeat`,
    }),
  }),
});

export const { useGetHeartbeatQuery } = globalSettingsApi;

The store:

import api from 'api'; // Aliased
const combinedReducers = combineReducers({
  [api.reducerPath]: api.reducer,
});

const middlewares = [];
middlewares.push(api.middleware);
export const store = configureStore({
  reducer: combinedReducers,
  middleware: getDefaultMiddleware =>
    getDefaultMiddleware({
      serializableCheck: false,
      immutableCheck: false,
    }).concat(middlewares),
  devTools: window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose,
});

The main:

import { Provider } from 'react-redux';
import { store } from 'Redux/store'; // alias from above store
import { Router } from './Router';
const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  <React.StrictMode>
    <Provider store={store}>
        <Router />
    </Provider>
  </React.StrictMode>,
);

Router:

export const routes = [
  {
    element: <Application />,
    children: [
      {
        element: <Public />,
        children: [
          { index: true, element: <IrrelevantElement /> },
        ],
      },
      {
        element: <Session />, // <--- This is the one we are reproducing the bug in
        children: [
            {
              path: 'activity',
              element: <IrrelevantElement />, // This is a valid component
            },
        ],
      },
    ]
}

Session

import { Outlet } from 'react-router';
import { useGetHeartbeatQuery } from 'Api/globalSettings';
export default Session = () => {
     useEffect(() => {
      const interval = setInterval(() => {
        console.log('component is still alive 1 second');
      }, 1000);
      return () => clearInterval(interval);
    }, []);
    useEffect(() => {
      const interval = setInterval(() => {
        console.log('component is still alive 10 seconds');
      }, 10000);
      return () => clearInterval(interval);
    }, []);
    const heartBeat = useGetHeartbeatQuery(undefined, {
      pollingInterval: 30000,
    });

    return (
        <>
           <Outlet />
       </>
    )
}

Expected behaviour
The expectation is that the polling timer should be cleared when the component dismounts.

Work around
The current workaround is to wrap the query in a useEffect and abort it on the return callback.

Comments
I tried to see if this has already been reported but I could not find anything, apologies if I have done anything wrong, kindly advise in comments and I will update accordingly! Thank you!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions