16
votes

I'm having trouble accessing saved data after app starts with redux-persist.

The reducer initializes with data defined in my initial state. By the time the previous session's state loads with AsyncStorage, the component is already displayed with the default data.

I know that the data is saved and fetched successfully. If I leave the screen to a different one and come back to it, I can see that the data is displayed correctly. Debugging the state and props also shows that this is a async timing issue.

How can I delay the loading of the redux containers to after the store rehydrates. Alternatively, can I force update the conatainer (and its children) to update when the store finishes loading?

Here is what I've tried. to configure my store:

export default function configureStore(initialState) {
    const middlewares = [thunk];
    if (process.env.NODE_ENV === `development`) {
        const createLogger = require(`redux-logger`);
        const logger = createLogger();
        middlewares.push(logger);
    }

    let store = compose(
        applyMiddleware(...middlewares),
        autoRehydrate() )(createStore)(reducers);

        persistStore(store, {blacklist: ['routing'], storage: AsyncStorage}, () => {
            store.dispatch(storeRehydrateComplete())
        })


    return store
}

Hoping that this will update all other components (since all reducers in redux are called in an action), I've tried creating an action that triggers when the store finishes loading:

import { REHYDRATE_STORE } from './types'

export function storeRehydrateComplete(){
    return {
        type: REHYDRATE_STORE,
    }
}

And it's reducer: import { REHYDRATE_STORE } from '../actions/types' const initialState = { storeIsReady: false }

export default function reducer(state = initialState, action){
    switch (action.type) {
        case REHYDRATE_STORE:
            return {...state, storeIsReady:true}
            break;
        default:
            return state
            break;
    }
}

But although the storeIsReady state changes to true when rehydration is complete, I'm still couldn't figure out how to force update the container component.

1
If you make the container receive storeIsReady mapStateToProps, does it trigger componentWillReceiveProps? Also, there is no need for your own action type, because you there is a special action in redux-persist for that, import {REHYDRATE} from 'redux-persist/constants';Konstantin Kuznetsov

1 Answers

10
votes

I solved it by following this recipe: delay-render-until-rehydration-complete

Basically the solution is as follows:
In the component that wraps <Provider>, create a local state flag that tracks whether the store has rehydrated yet or not. Using the callback of persistStore() to update this flag. In the render function of this wrapper, if the flag is true, render <Provider>, otherwise, render some temporary view.