Skip to content

RTK Query gets stuck in "pending" state when following the persistence example from the website #4715

Open
@GertSallaerts

Description

@GertSallaerts

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:

  1. You've set up redux-persist to persist the api reducer, not the root reducer.
  2. None of the queries that get rehydrated are fulfilled or rejected, e.g. they were all pending when the app got interrupted
  3. You're using autoMergeLevel1 as state reconciler for redux persist
  4. 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:

  1. The app loads, state is initialized, etc.
  2. The current state of your api slice looks a bit like this: { queries: {}, mutations: {}, config: {...} }
  3. redux-persist's REHYDRATE action is triggered
  4. Our extractRehydrationInfo runs and returns the REHYDRATE payload to RTKQ
  5. RTKQ takes that payload and sets all queries that are either fulfilled or rejected on the queries object. In our case that's none of them (condition 2 above.) This happens here:
    const { queries } = extractRehydrationInfo(action)!
    for (const [key, entry] of Object.entries(queries)) {
    if (
    // do not rehydrate entries that were currently in flight.
    entry?.status === QueryStatus.fulfilled ||
    entry?.status === QueryStatus.rejected
    ) {
    draft[key] = entry
    }
    }
  6. At the end of REHYDRATE, redux-persist will use autoMergeLevel1 to do a shallow compare between the state before and after REHYDRATE. It will not detect any changes to the queries 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#L24
  7. 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.

Example

I've set up a minimal example that shows the issue here: https://codesandbox.io/p/sandbox/qpv4m9

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.)
  • Writing a transform for redux-persist that doesn't persist these pending queries in the first place

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.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions