When you set up your store to persist your api reducer as outlined on the website, there's a chance your persisted queries get stuck in "pending" state if the app gets interrupted while fetching a query (e.g. the window is reloaded.) This only happens when a few conditions are met:
You've set up redux-persist to persist the api reducer, not the root reducer.
None of the queries that get rehydrated are fulfilled or rejected, e.g. they were all pending when the app got interrupted
You're using autoMergeLevel1 as state reconciler for redux persist
You're using extractRehydrationInfo in your api slice as documented on the website
When both those condition are met, the following will happen upon rehydration:
The app loads, state is initialized, etc.
The current state of your api slice looks a bit like this: { queries: {}, mutations: {}, config: {...} }
redux-persist's REHYDRATE action is triggered
Our extractRehydrationInfo runs and returns the REHYDRATE payload to RTKQ
RTKQ will not load the data for those queries anymore because (since they're in pending state) it's waiting for them to complete which they will never do.
Inside the getPokemonByName endpoint, it does a window.reload() to simulate the user reloading the page. So if the code worked, the example would be in an infinite reload loop. Instead it will rehydrate the pending query from localStorage after the first reload and get stuck there.
Towards a solution
I don't think there's a bug in redux-persists, nor in RTK Query. Both work as advertised by themselves.
The problem is that the example code on the RTK website on how to make them work together doesn't work in all scenarios. I can think of two ways to resolve this:
Using a custom state reconciler, I think it could be as simple as writing one that always uses the so-called reducedState (i.e. just use whatever is returned by the api reducer during REHYDRATE.)
I'm happy to help out on either one but I'd be interested in hearing the team's thoughts on this first.
I'm assuming you would like to prevent having any kind of redux-persist-specific code in the library?
Do you see this as something that gets written out fully in the documentation page on the website for people to copy-paste?
Would you be willing to either maintain or link to a separate transform package for redux-perist? (e.g. redux-persist-transform-rtk-query like the others they list on their README by independent developers.)
Problem description
When you set up your store to persist your api reducer as outlined on the website, there's a chance your persisted queries get stuck in "pending" state if the app gets interrupted while fetching a query (e.g. the window is reloaded.) This only happens when a few conditions are met:
autoMergeLevel1
as state reconciler for redux persistextractRehydrationInfo
in your api slice as documented on the websiteWhen both those condition are met, the following will happen upon rehydration:
{ queries: {}, mutations: {}, config: {...} }
REHYDRATE
action is triggeredextractRehydrationInfo
runs and returns theREHYDRATE
payload to RTKQfulfilled
orrejected
on thequeries
object. In our case that's none of them (condition 2 above.) This happens here: https://github.com/reduxjs/redux-toolkit/blob/24286f1745e42217448de1f3486886fa8558c1b5/packages/toolkit/src/query/core/buildSlice.ts#L390-L399REHYDRATE
, redux-persist will useautoMergeLevel1
to do a shallow compare between the state before and after REHYDRATE. It will not detect any changes to thequeries
subkey of the state at this point and resort to retaining what it loaded from storage (i.e. the pending queries.) This happens here: https://github.com/rt2zz/redux-persist/blob/d8b01a085e3679db43503a3858e8d4759d6f22fa/src/stateReconciler/autoMergeLevel1.ts#L24Example
I've set up a minimal example that shows the issue here: https://codesandbox.io/p/sandbox/qpv4m9
Inside the
getPokemonByName
endpoint, it does awindow.reload()
to simulate the user reloading the page. So if the code worked, the example would be in an infinite reload loop. Instead it will rehydrate the pending query from localStorage after the first reload and get stuck there.Towards a solution
I don't think there's a bug in redux-persists, nor in RTK Query. Both work as advertised by themselves.
The problem is that the example code on the RTK website on how to make them work together doesn't work in all scenarios. I can think of two ways to resolve this:
reducedState
(i.e. just use whatever is returned by the api reducer duringREHYDRATE
.)I'm happy to help out on either one but I'd be interested in hearing the team's thoughts on this first.
redux-persist
-specific code in the library?redux-persist-transform-rtk-query
like the others they list on their README by independent developers.)