rt2zz / redux-persist

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

Redux Persist not working on IOS... works well on android #764

Open sarathvad1811 opened 6 years ago

sarathvad1811 commented 6 years ago

Redux persist works on android but is not working on IOS 11.0 my code is as below

// store.js
export const configureStore(intialState){
const rootPersistConfig = {
  key: "root",
  storage: storage,
  debug: true
};

const persistedReducer = persistReducer(rootPersistConfig, rootReducer);

middlewares = [...];

let store = createStore(
    persistedReducer,
    initialState,
    composeEnhancers(applyMiddleware(...middlewares))
  );
let persistor = persistStore(store);
return { persistor, store };
}

and my app.js is as follows

// app.js
// other imports
const { persistor, store } = configureStore({});

export default App extends Component {
// all other things

render() {
    return (
      <Provider store={store}>
        <AlertProvider>
          <Root>
            <PersistGate persistor={persistor} loading={null}>
              <RootNav />
            </PersistGate>
          </Root>
        </AlertProvider>
      </Provider>
    );
  }
}

I also had redux-logger which I checked in the console neither the PERSIST event nor REHYDRATE occurs. The persistGate never gets lifted. Please help stuck from past 4 days. :( thanks in advance

ltankey commented 6 years ago

Argh I'm having the opposite - works fine on iOS simulator but not on a connected Android device! Hopefully it's a related issue and someone can respond...

sarathvad1811 commented 6 years ago

yeah :(

jamsch commented 6 years ago

Currently am using redux-persist@5.9.1 in a large production app right now on Android and it's great, no problems besides the RN remote debugging AsyncStorage bug. About to release an iOS app however testing on a real device has had it stuck at the persist gate a few times while testing the app. When it gets stuck the only way to fix it is to reinstall because subsequent launches wouldn't persist either. I just can't pinpoint why it would not persist either and am hesitant to release an app utilising this library right now.

It doesn't seem to matter whether you're using the default RN filesystem import or redux-persist-filesystem-storage. It also doesn't seem to matter what kind of transforms your app is doing when reading/writing data. The persist timeout config doesn't seem to have any effect either.

ltankey commented 6 years ago

I managed to get this working, but not by doing anything special. It turns out that while in debug mode in expo, it fails to run the rehydrate action and therefore any subsequent persist resets the state of the app.

You can fix this by turning off debug and reloading the app. Things will then go back to working normally. I find this only happens if I try to reload the app while still in debug mode.

evertonco commented 5 years ago

Little late, but, I noticed redux persist REHYDRATE action was executing before main component be mounted. So, just checking prop _persist.rehydrated on componentWillMount method of main component was enough to me.

yasso1am commented 5 years ago

Little late, but, I noticed redux persist REHYDRATE action was executing before main component be mounted. So, just checking prop _persist.rehydrated on componentWillMount method of main component was enough to me.

Could you elaborate on the function you wrote to check this, and where you implemented it?

evertonco commented 5 years ago

App.js

export default class App extends React.Component {
  render() {
    return (
      <ApolloProvider client={client} store={store}>
        <AppNavigator {...this.props} />
      </ApolloProvider>
    );
  }
}

navigator.js

export const AppNavigator = createSwitchNavigator(
  {
    AppLoading,
    App,
    Auth,
  },
);

app-loading.js

class AppLoading extends Component {

  storeReady = false;
  // other variable definitions

  state = {};

  componentWillMount() {

    const { _persist } = this.props;

    // set flag (expected be true)
    this.storeReady = _persist.rehydrated;
    ...
  }

  componentWillReceiveProps({ _persist }) {

    // check for REHYDRATE event (On IOS, this event is not fired. On android, works correctly)
    if (!this.props._persist.rehydrated && _persist.rehydrated) {

      this.storeReady = true;
      ...
    }
  }

  // I'm using Expo. So, I check if this.storeReady flag is true to allow app to go to next screen:
  handleFinishLoading = () => {
    if(this.storeReady) {
      // logic to check if user is authenticated or other stuff and redirect to correct screen
      this.props.navigation.navigate('NextScreen');
    } else {
       // redirect to error screen?!
    }
  }

  render() {
    return (
      <Expo.AppLoading
        startAsync={this.handleLoadResources}
        onError={this.handleLoadingError}
        onFinish={this.handleFinishLoading}
      />
    );
  }
}

// redux mapping to get access to _persist prop
const mapStateToProps = ({ _persist }) => ({ _persist });

export default connect(mapStateToProps)(AppLoading);