Jiew Meng
Jiew Meng

Reputation: 88317

Redux persist rehydrate previous auth state too late

I have setup routes that are meant to be authenticated to redirect user to login page if unauthenticated. I have also setup redux-persist to auto dehydrate my auth state so user remains login on refresh. The problem is this rehydration is too late and user is already redirected to login page

enter image description here

The 1st location change is to an authenticated route, the 2nd is to login. Notice rehydrate comes after these. Ideally it should be right after @@INIT at least?

Upvotes: 13

Views: 6535

Answers (2)

haipham23
haipham23

Reputation: 476

When user refresh the page, The first LOCATION_CHANGE will fire because you sync history with store. However, it only syncs the history and does not redirect user to anywhere yet.

The only thing matters is the second LOCATION_CHANGE, which should occur after persistStore(). Good news is persistStore() has a call back.

const store = ...

// persist store
persistStore(store, options, () => {
  const states = store.getState();

  // if authenticated, do nothing,
  // if not, redirect to login page
  if (!states.auth.isAuthenticated) {
    // redirect to login page
  }
});

render(...);

Hope this can help to solve your problem.

Upvotes: 0

fkulikov
fkulikov

Reputation: 3199

The persistStore function which is used to make your store persistent have a third param callback which is invoked after store rehydration is done. You have to start your app with some sort of preloader, which waits for rehydration to happen and renders your full application only after it finishes.

redux-persist docs even have a recipe for this scenario. In your case all the react-router stuff should be rendered inside initial loader as well:

export default class Preloader extends Component {

  constructor() {
    super()
    this.state = { rehydrated: false }
  }

  componentWillMount(){
    persistStore(this.props.store, {}, () => {
      this.setState({ rehydrated: true });
    })
  }

  render() {
    if(!this.state.rehydrated){
      return <Loader />;
    }
    return (
      <Provider store={store}>
        <ConnectedRouter history={history}>
          <App />
        </ConnectedRouter>
      </Provider>
    );
  }
}

const store = ...; // creating the store but not calling persistStore yet
ReactDOM.render(<Preloader store={store} />, ... );

Upvotes: 19

Related Questions