Minimal reproduction case to illustrate a problem observed with server-side execution of redux-toolkit queries.
To run the demo, run npm start, and point the browser at localhost:3000.
The response will be artificially delayed for 2 seconds, after which time the page returns a serialized redux store.
If you quickly refresh the browser several times while the initial request has not yet completed (thus simulating several concurrent requests on the server), you will notice multiple subscriptions in restApi slice:
{
"restApi": {
"queries": {
"test(undefined)": {
"status": "fulfilled",
"endpointName": "test",
"requestId": "WJig5NVQAXSdFfe4oihot",
"startedTimeStamp": 1760998513707,
"data": {
"foo": "bar"
},
"fulfilledTimeStamp": 1760998515709
}
},
"mutations": {},
"provided": {
"tags": {},
"keys": {
"test(undefined)": []
}
},
"subscriptions": {
"test(undefined)": {
"J9x7_VFiN6IVh4VyN1Y72": {},
"ZqlzHRB3_Hs30xYc0Qe7E": {},
"CdKKLI737XGoJDFcMTugK": {},
"0k7xz9pCko_z-z1IcwlKn": {},
"WJig5NVQAXSdFfe4oihot": {}
}
},
"config": {
"online": true,
"focused": true,
"middlewareRegistered": true,
"refetchOnFocus": false,
"refetchOnReconnect": false,
"refetchOnMountOrArgChange": false,
"keepUnusedDataFor": 60,
"reducerPath": "restApi",
"invalidationBehavior": "delayed"
}
}
}Note that if you switch the query function in src/state/api-slices/testSlice.ts to the commented one that finishes fast (without the artificial timeout), then despite fast refreshes, and despite the lack of unsubscribe-ing from the redux endpoint, you will always receive a clean store no matter how often you refresh the page. The response will always look like this - with empty subscriptions:
{
"restApi": {
"queries": {
"test(undefined)": {
"status": "fulfilled",
"endpointName": "test",
"requestId": "7UXOewKDX0lNJXwsMfUdJ",
"startedTimeStamp": 1760999662052,
"data": {
"foo": "bar - 391"
},
"fulfilledTimeStamp": 1760999662053
}
},
"mutations": {},
"provided": {
"tags": {},
"keys": {
"test(undefined)": []
}
},
"subscriptions": {},
"config": {
"online": true,
"focused": true,
"middlewareRegistered": true,
"refetchOnFocus": false,
"refetchOnReconnect": false,
"refetchOnMountOrArgChange": false,
"keepUnusedDataFor": 60,
"reducerPath": "restApi",
"invalidationBehavior": "delayed"
}
}
}