rt2zz / redux-persist

persist and rehydrate a redux store
MIT License
12.94k stars 866 forks source link

PersistGate rendering before persist/REHYDRATE is complete #1178

Open sabun123 opened 4 years ago

sabun123 commented 4 years ago

Hi there,

Issue: PersistGate gets permission to render before persist/REHYDRATE is actually complete. Both the _persist.rehydrated and bootstrapped values are true even before the persistStore callback function is fired. This is on the web, using React 16.7.

Versions I've tried:

Details: What happens is that PersistGate gets it's bootstrapped value set to true, but the persistStore callback function that helps determine when the rehydration process is complete is only ran after this. This basically means that on browser refresh, the app renders before my authorization tokens get set so any API calls fail.

What could I be doing wrong?

Code:

App.js

const initialState = {};
const { persistor, store } = configureStore(initialState);
const MOUNT_NODE = document.getElementById("root");

const render = messages => {

  ReactDOM.render(
    <Provider store={store}>
       <PersistGate persistor={persistor}>
         { (bootstrapped) => {
           if(bootstrapped){
             console.log('bootstrapped', bootstrapped);
             return ( <App />)
           } else {
             return null;
           }
         }}

      </PersistGate>
    </Provider>,
    MOUNT_NODE
  );
};

store.js

...
export default function configureStore(initialState = {}) {
  // Create the store with two middlewares
  // x. sagaMiddleware: Makes redux-sagas work
  const middlewares = [
    sagaMiddleware,
  ];

  const enhancers = [applyMiddleware(...middlewares)];

  // If Redux DevTools Extension is installed use it, otherwise use Redux compose
  /* eslint-disable no-underscore-dangle */
  const composeEnhancers =
    process.env.NODE_ENV !== 'production' &&
    typeof window === 'object' &&
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
      ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
          shouldHotReload: false, // eslint-disable-line
        }) // eslint-disable-line
      : compose;
  /* eslint-enable */

  const store = createStore(
    persistedReducer,
    initialState,
    composeEnhancers(...enhancers),
  );

  // Extensions

  const persistor = persistStore(store, {}, () => {

    // on redux persist rehydrate, if token is still valid
    // re-add it to axios headers
    // good example of when rehydrate occurs is on browser refresh (F5)
    const state = store.getState();

    console.log('finished REHYDRATING-----')

    if(state.auth.accessToken){
      // On rehydrating persistence (or basically refresh the page), we set the axios headers with the token
      console.log('====== setting header access token')
      axios.defaults.headers.common["Authorization"] = `Bearer ${state.auth.accessToken}`;

      console.log('state.auth.accessToken ',state.auth.accessToken)
      console.log('axios.defaults.headers', axios.defaults.headers)
    }
  });

  store.runSaga = sagaMiddleware.run(rootSaga);

  return { persistor, store };
}

Logging it out: Screenshot 2020-03-23 at 1 44 42 PM

Notice that the rehydration completes AFTER persistGate has already allowed the app to render. My understanding is that PersistGate is supposed to prevent rendering until after rehydration is complete. (token not logged out for privacy reasons here).

meddy commented 4 years ago

@sabun123 I thought I was seeing the same behavior. But what is actually happening for me is that sagas are running before rehydrate is dispatched. So I just need to gate the sagas in a similar fashion, take('persist/rehydrate'). Are you sure you aren't running into something similar, since I see you are using sagaMiddleware as well?

wmonecke commented 3 years ago

@sabun123 Any updates?

anwarhamr commented 2 years ago

I too am having he same issue.
I see in the debugger that these actions are happening on app load 1) @@init happens - my loading component is shown 2) persist/PERSIST - happens and the gate appears to lift because my component inside persystGate is rendered! Should not be correct? 3) persist/REHYDRATE - comes next and my state is loaded and onBeforeLift is called 4) more actions...

Why is persist/PERSIST being called at all when we are loading from storage? Why is the gate being released before rehydrate?