2
votes

I want to set a condition to either completely persist/rehydrate the store, or not based on whether or not the app is recovering from an error.

In the top level component (app.js), I am importing the store and persistor (from MyStore.js), and wrapping the rest of the app in the Provider and the PersistGate. The store is in a separate file so that it can be imported and read by some shared logic files.

When the app component loads, it checks AsyncStorage to see if it's recovering from an error, and updates the state. I want that state to determine if the store gets persisted.

Would love any suggestions

// ......... App.js:

componentDidMount = () => { this.checkForPreviousFatalError() }

checkForPreviousFatalError = async () => {
    var array = null
    try {
        array = await AsyncStorage.multiGet(['@lastFatalErrorEpoch', '@previousFatalErrorEpoch'])
    } catch(e) {
        console.log( "Unable to retrieve date of last 2 errors: " + e );
    }
    const lastError = array[0][1];
    const prevError = array[1][1];

    if ( lastError && prevError && parseInt(prevError) + 60000 > parseInt(lastError) ) {
        // do not persist store
    } else {
        // persist store
    };

}

render() {
    const waitingElement = (
        <ImageBackground source={require('./assets/signInBackground.jpg')} style={[ Styles.flexCenter, Styles.flexColumn, { height: "100%" }]}>
            <Text style={{ fontSize: 18, marginBottom: 20 }} >{ EnglishNA.RestoringLocalData }</Text>
            <Spinner size='large' flexZero={ true } color="white" />
        </ImageBackground>
    )

    return (
        <Provider store={ store }>
            <PersistGate loading={ waitingElement } persistor={ persistor }>
                <LogIn />
            </PersistGate>
        </Provider>
    )

}
}

// ....... MyStore.js

import ReduxThunk from 'redux-thunk';
import { createStore, applyMiddleware } from 'redux';
import ServerCall from './services/ServerCall';
import rootReducer from './reducers'; 
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';

const persistConfig = {
key: 'root',
storage: storage,
stateReconciler: autoMergeLevel2 // see "Merge Process" section for details.
};

const pReducer = persistReducer(persistConfig, rootReducer);

export const store = createStore( pReducer, applyMiddleware( ReduxThunk, ServerCall ) );
export const persistor = persistStore(store);
1

1 Answers

0
votes

You should configure store after calling function checkForPreviousFatalError. If there is error do not persist store and do not use persistReducer in store. For loading you can use component state.

Like this:

const pReducer = persist
    ? persistReducer(persistConfig, rootReducer)
    : rootReducer;

App.js

// ......... App.js:
import configureStore from "./MyStore.js";

//....................

state = {
    isLoading: true,
    store: null
  };

componentDidMount = () => { this.checkForPreviousFatalError() }

checkForPreviousFatalError = async () => {
    var array = null
    try {
        array = await AsyncStorage.multiGet(['@lastFatalErrorEpoch', '@previousFatalErrorEpoch'])
    } catch(e) {
        console.log( "Unable to retrieve date of last 2 errors: " + e );
    }
    const lastError = array[0][1];
    const prevError = array[1][1];

    if ( lastError && prevError && parseInt(prevError) + 60000 > parseInt(lastError) ) {
         this.configureStore(false)
        // do not persist store
    } else {
       this.configureStore(true)
        // persist store
    };

}

configureStore = (persist) => {
    configureStore(persist, store => {
      this.setState({ isLoading: false, store });
    });
  }

render() {
    if (this.state.isLoading) {
      return <ImageBackground source={require('./assets/signInBackground.jpg')} style={[ Styles.flexCenter, Styles.flexColumn, { height: "100%" }]}>
            <Text style={{ fontSize: 18, marginBottom: 20 }} >{ EnglishNA.RestoringLocalData }</Text>
            <Spinner size='large' flexZero={ true } color="white" />
        </ImageBackground>;
    }

    return (
      <View style={{ flex: 1 }}>
        <Provider store={this.state.store}>
          <AppNavigator />
        </Provider>
        {this._renderStatusBarIos()}
        <MessageBar />
      </View>
    );
  }


MyStore.js file

import ReduxThunk from "redux-thunk";
import { createStore, applyMiddleware } from "redux";
import ServerCall from "./services/ServerCall";
import rootReducer from "./reducers";
import { persistStore, persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
import autoMergeLevel2 from "redux-persist/lib/stateReconciler/autoMergeLevel2";

let store;

export default function configureStore(persist, onComplete: Function) {
  const persistConfig = {
    key: "root",
    storage: storage,
    stateReconciler: autoMergeLevel2 // see "Merge Process" section for details.
  };

  const pReducer = persist
    ? persistReducer(persistConfig, rootReducer)
    : rootReducer;

  store = createStore(pReducer, applyMiddleware(ReduxThunk, ServerCall));
  persistStore(store, null, () => onComplete(store));
}


if you want to export store make a function in MyStore.js

export function getStore() {
  return store;
}