0

I'm using redux-offline in my React app and things look good except that the values "flicker" when the page first loads. For less than a second, I can see the initial value of a store variable before it's replaced with the persisted value.

Is there a fix for this?

Here is my store code:

import { reducer as reduxFormReducer, FormStateMap } from 'redux-form';
import { connectRouter, routerMiddleware, RouterState } from 'connected-react-router';
import { combineReducers, createStore, applyMiddleware, Store, compose } from 'redux';
import { History, createBrowserHistory } from 'history';
import { offline, createOffline } from '@redux-offline/redux-offline';
import offlineConfig from '@redux-offline/redux-offline/lib/defaults';
import thunk from 'redux-thunk';

// state
export interface IAppState {
    readonly form: FormStateMap;
    readonly router: RouterState;
    ...
}

// tslint:disable-next-line:no-empty
export const neverReached = (never: never) => {};

export const history = createBrowserHistory();

const rootReducer = ((history: History) => combineReducers<IAppState>({
    form: reduxFormReducer,
    router: connectRouter(history),
    ...
}))(history);

const { middleware, enhanceReducer, enhanceStore } = createOffline(offlineConfig);

export function configureStore(): Store<IAppState> {
    // This line is suspect, not sure if this is the middleware required
    const store = createStore(
        enhanceReducer(rootReducer), 
        undefined,
        compose(
            applyMiddleware(middleware, routerMiddleware(history), thunk),
            enhanceStore));

    return store;
}
Tyler Findlay
  • 607
  • 1
  • 4
  • 19
  • 1
    Not sure if there's a better/more officially supported way but with redux-persist we render our splash screen until the rehydrate event is dispatched. So basically adding a flag in your initial state that indicates that the rehydration stage hasn't completed yet and update the flag on the rehydrate event or whatever the redux-offline equivalent is. – azundo Nov 12 '19 at 04:26
  • What does that callback look like? I founds some samples, but my application is in Typescript. I couldn't get the rehydrate action to trigger. – Tyler Findlay Nov 12 '19 at 16:05
  • 1
    redux-persist should be dispatching the rehydrate action - we do `import {REHYDRATE} from 'redux-persist/constants';` and then have a reducer that does something similar to updating its state from `rehydrated: false` to `rehydrated: true` on the `REHYDRATE` action (our version is a little more complex but that's the basic idea), and then our `App` component renders our splash page while `rehydrated` is `false`. – azundo Nov 12 '19 at 19:39
  • @azundo do you have a public GitHub repo I could look at? I tried something similar but couldn't get it to work, but I might be missing a configuration. It might also be that getting things up in Typescript is a bit different – Tyler Findlay Nov 12 '19 at 20:11
  • @azundo I should also note `import {REHYDRATE} from 'redux-persist/constants';` isn't in `redux-offline` because it hides the `redux-persist` library mostly – Tyler Findlay Nov 12 '19 at 21:30
  • 1
    Sorry, no public github repo. Looks like redux-offline re-exports the constant from it's constants files: https://github.com/redux-offline/redux-offline/blob/develop/src/constants.js so try `import {PERSIST_REHYDRATE} from '@redux-offline/redux-offline/lib/constants';` instead. Depending on where you create your store it looks like the `offlineConfig` takes a `persistCallback` key that you could use to `setState` on your root component which might ultimately be a better solution: https://github.com/redux-offline/redux-offline/blob/develop/src/index.js#L75 – azundo Nov 12 '19 at 22:09
  • @azundo I'll give that a try. Want to write that in as a solution and if it works I'll mark it as the right one? – Tyler Findlay Nov 13 '19 at 15:20
  • 1
    Sounds good - just to clarify - the `persistCallback` one or the `PERSIST_REHYDRATE` one? – azundo Nov 13 '19 at 17:42
  • The `PERSIST_REHYDRATE` one – Tyler Findlay Nov 13 '19 at 21:28

1 Answers1

1

You can keep track of when state has been rehydrated by updating redux state based on the redux-persist REHYDRATE action. redux-offline re-exports the action type constant as PERSIST_REHYDRATE. A simple reducer like the one below should suffice.

import {PERSIST_REHYDRATE} from '@redux-offline/redux-offline/lib/constants';

function rehydratedReducer = (state = {rehydrated: false}, action) {
  if (action.type === PERSIST_REHYDRATE) {
    return {rehydrated: true};
  }
  return state;
}
azundo
  • 5,902
  • 1
  • 14
  • 21