Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

persist/REHYDRATE payload and err is undefined #719

Open
tonykawa opened this issue Feb 13, 2018 · 24 comments
Open

persist/REHYDRATE payload and err is undefined #719

tonykawa opened this issue Feb 13, 2018 · 24 comments

Comments

@tonykawa
Copy link

tonykawa commented Feb 13, 2018

image
I use redux-persist 5.7.2 with react-starter-kit.
I tried 5.6.12, it doesn't run persist/REHYDRATE.
configureStore.js
const authPersistConfig = { key: 'root', storage: storageSession, };
export default function configureStore(initialState, helpersConfig) {
const helpers = createHelpers(helpersConfig);
const middleware = [thunk.withExtraArgument(helpers)];
let enhancer;
if (__DEV__) {
middleware.push(createLogger());
let devToolsExtension = f => f;
if (process.env.BROWSER && window.devToolsExtension) {
devToolsExtension = window.devToolsExtension(); }
enhancer = compose(applyMiddleware(...middleware), devToolsExtension);
} else {
enhancer = applyMiddleware(...middleware);}
const rootReducer = createRootReducer();
const persistedReducer = persistReducer(authPersistConfig, rootReducer);
const store = createStore(persistedReducer, initialState, enhancer);
if (__DEV__ && module.hot) {
module.hot.accept('../reducers', () =>
if you change reducers back to normal rootReducer.
store.replaceReducer(require('../reducers').default()),
);}
const persistor = persistStore(store);
return { store, persistor };
}

Do i set it wrong?

part of client.js
const { store, persistor } = configureStore(window.App.state, { apolloClient, fetch, history, });

const renderReactApp = isInitialRender ? ReactDOM.hydrate : ReactDOM.render;
appInstance = renderReactApp(
<App context={context}>
<PersistGate loading={null} persistor={persistor}>
{route.component}
</PersistGate>
</App>,container,
() => {
if (isInitialRender) {
const elem = document.getElementById('css');
if (elem) elem.parentNode.removeChild(elem);
return;
}
The PersistGate in server.js is same as client.js

@tonykawa tonykawa changed the title persist/REGYDRATE payload and err is undefined persist/REHYDRATE payload and err is undefined Feb 13, 2018
@rt2zz
Copy link
Owner

rt2zz commented Feb 13, 2018

are you using android? react native AsyncStorage has a bug with android when the debugger is open causing this to happen. As you can see the persist is timing out (check the error on the REHYDRATE action).

The only workaround for this is to use a different storage engine: https://github.com/rt2zz/redux-persist#storage-engines

@tonykawa
Copy link
Author

No, i am writing website using react

@rt2zz
Copy link
Owner

rt2zz commented Feb 13, 2018

hm, then possibly a bug with storageSession? You could try using localForage (https://github.com/localForage/localForage) and see if that works?

@tonykawa
Copy link
Author

tonykawa commented Feb 13, 2018

[13:12:54] Finished 'server' compilation after 15634 ms
[13:12:54] Launching server...
redux-persist failed to create sync storage. falling back to memory storage.
...
persist/REHYDRATE: { type: 'persist/REHYDRATE', payload: undefined, err: undefined, key: 'root' }
This is the error message when i yarn start my project.

@rt2zz
Copy link
Owner

rt2zz commented Feb 13, 2018

ah interesting, so session storage is failing - that explains the behavior. We need to figure out why.

That means this line is failing: https://github.com/rt2zz/redux-persist/blob/master/src/storage/getStorage.js#L35

are you running this in a standard browser? Is it a private browsing session perhaps?

@tonykawa
Copy link
Author

tonykawa commented Feb 13, 2018

I run in the latest chrome and tried localstorage & LOCALFORAGE, but also fail.
I move PersistGate from client.js to App.js and create persist reducer to show all persist action.

export default function persist(state = null, action) {
console.warn(action);
switch (action.type) {
case 'persist/REHYDRATE':
return {
...state,
persistedState: action.payload,
};
default:
return state;}}

This is the result.
I can get the previous result (user), before execute the persist/REHYDRATE.
image

After executed the persist/REHYDRATE, the result was set to null (user).

@rt2zz
Copy link
Owner

rt2zz commented Feb 14, 2018

Ok I see REHYDRATE is being called twice, can you make sure you are on the latest version of redux persist? I believe 5.7.x may have had a bug causing this

@tonykawa
Copy link
Author

tonykawa commented Feb 15, 2018

yes, the redux persist version in my project is 5.8.0. however, the result is same as 5.7.2.

@challme28
Copy link

I have to say I've been stuck in this problem for a while now and it was my fault. I forgot to return an action on an Epic. I hope this helps anyone

@atav32
Copy link

atav32 commented Mar 1, 2018

@challme28 could you explain a little more? maybe a code snippet?

@atav32
Copy link

atav32 commented Mar 1, 2018

@tonykawa you can use ``` code in here ``` for multi-line code fragments. It gets rendered nicely, for example

// configureStore.js

const authPersistConfig = {
  key: 'root',
  storage: storageSession,
};
export default function configureStore(initialState, helpersConfig) {
  const helpers = createHelpers(helpersConfig);
  const middleware = [thunk.withExtraArgument(helpers)];
  let enhancer;
  if (__DEV__) {
    middleware.push(createLogger());
    let devToolsExtension = f => f;
    if (process.env.BROWSER && window.devToolsExtension) {
      devToolsExtension = window.devToolsExtension();
    }
    enhancer = compose(applyMiddleware(...middleware), devToolsExtension);
  } else {
    enhancer = applyMiddleware(...middleware);
  }
  const rootReducer = createRootReducer();
  const persistedReducer = persistReducer(authPersistConfig, rootReducer);
  const store = createStore(persistedReducer, initialState, enhancer);
  if (__DEV__ && module.hot) {
    module.hot.accept('../reducers', () =>
      // if you change reducers back to normal
      rootReducer.store.replaceReducer(require('../reducers').default()),
    );
  }
  const persistor = persistStore(store);
  return {
    store,
    persistor
  };
}

Markdown:
screen shot 2018-03-01 at 11 43 39 am

@challme28
Copy link

@tonykawa
I had it like this:

export function rehydrateEpic(action$: ActionsObservable<RehydrateAction>) {
  return action$.ofType(REHYDRATE)
    .mergeMap(({ payload }) => {
        const { authenticated } = payload.auth;
        if (authenticated) {
          return Observable.of(HomeAction)
        }
    });
}

If the user is not authenticated it does not return anything so Rehydrated is called again

Ok I see REHYDRATE is being called twice

So i had to add a else return Observable.of(notAuthenticated());. This stopped the second call on REHYDRATE

@atav32
Copy link

atav32 commented Mar 1, 2018

@rt2zz is dispatching REHYDRATE twice a bug?

@atav32
Copy link

atav32 commented Mar 1, 2018

only happening when the storage is empty, so there's nothing to hydrate from?

@rt2zz tried the different storage engines (localStorage, sessionStorage, localForage), but all of them are showing the same error:

screen shot 2018-03-01 at 1 56 26 pm

@atav32
Copy link

atav32 commented Mar 1, 2018

Temporary workaround is to check if action.payload is defined

export const app = (state = appDefaultState, action) => {
  switch (action.type) {
    case REHYDRATE:
      if (action.payload) { // <- I guess this works, but it's kinda ugly
        return {
          ...state,
          user: action.payload.user,
        };
      } else {
        return state;
      }

    ...

@rt2zz
Copy link
Owner

rt2zz commented Mar 2, 2018

@atav32 you are seeing persist dispatched twice when there is no prior storage? That is definitely a bug, but I dont see how that can happen as we only allow rehydrate to be called once (per persistReducer): https://github.com/rt2zz/redux-persist/blob/master/src/persistReducer.js#L71-L86

@mattmcdonald-uk
Copy link

I have the same issue.

Using version 5.9.1 I get an undefined payload if there's nothing in localstorage (same with localForage).

@atav32
Copy link

atav32 commented Mar 20, 2018

@mattmcdonald-uk I just ended up doing this, https://egghead.io/lessons/javascript-redux-persisting-the-state-to-the-local-storage

@YCMitch
Copy link

YCMitch commented Sep 25, 2019

@rt2zz I'm still still getting these issues, although they only seem to affect random devices. In my office there's 10 of us using my app, and only 2 people seem to get this.

In my case, rehydrate only happens once, but payload and err are both empty. Is it perhaps a memory issue?

@kent2508
Copy link

kent2508 commented Nov 4, 2019

put on code in a lazy component (200-300 ms) and your project will work again.
Example:
<LazyComponent> <Provider>...</Provider> </LazyComponent>

@DeVoresyah
Copy link

@rt2zz I'm still still getting these issues, although they only seem to affect random devices. In my office there's 10 of us using my app, and only 2 people seem to get this.

In my case, rehydrate only happens once, but payload and err are both empty. Is it perhaps a memory issue?

same issue, but in my case, it happens when hermes engine is enabled

@ondrejkolin
Copy link

I experienced very similar issue caused by my store. Make sure you always return something from the store. Even if you don't plan to change anything.

I was missing the default branch for following switch.

 case USER_LOGIN:
            return {
                ...state,
                ...action.payload
            }
        case USER_LOGOUT:
            return {
                ...state,
                user: undefined
            }
        default:
            return state

@yestay90
Copy link

@rt2zz I'm still still getting these issues, although they only seem to affect random devices. In my office there's 10 of us using my app, and only 2 people seem to get this.
In my case, rehydrate only happens once, but payload and err are both empty. Is it perhaps a memory issue?

same issue, but in my case, it happens when hermes engine is enabled

@DeVoresyah hello, have you figured out why we have timeout error after Hermes is enabled?

@sanduluca
Copy link

As i said in #786 :

The author is using a variable outside of setTimeout to know if the state was not rehydrated.

https://github.com/rt2zz/redux-persist/blob/master/src/persistReducer.ts#L72-L101

The problem here is that _sealed is not changed to true because a error is thrown in action.rehydrate(config.key, payload, err); and this is already your problem.

Changing the order here would fix the issue with double rehydration and the timeout error message. This will alse reveal the probleme in the developers code. I would also add a try catch block to console.error the error
https://github.com/rt2zz/redux-persist/blob/master/src/persistReducer.ts#L86-L87

Here is a patch-package

diff --git a/node_modules/redux-persist/lib/persistReducer.js b/node_modules/redux-persist/lib/persistReducer.js
index 1116881..9ce961b 100644
--- a/node_modules/redux-persist/lib/persistReducer.js
+++ b/node_modules/redux-persist/lib/persistReducer.js
@@ -70,8 +70,12 @@ function persistReducer(config, baseReducer) {
         if (process.env.NODE_ENV !== 'production' && _sealed) console.error("redux-persist: rehydrate for \"".concat(config.key, "\" called after timeout."), payload, err); // only rehydrate if we are not already sealed
 
         if (!_sealed) {
-          action.rehydrate(config.key, payload, err);
           _sealed = true;
+          try {
+            action.rehydrate(config.key, payload, err);
+          } catch (error) {
+            console.error("redux-persist: rehydrate for \"".concat(config.key, "\" failed"), error);
+          }
         }
       };
 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests