Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React router, how to restore state after browser back button?

I'm trying to figure out how to make my React SPA app maintain state when the user navigates with the back/forward browser buttons. E.g. the user is filling a form, then he moves back and forward and the form is automatically restored.

I reviewed many JavaScript routers around but none seem to address this issue properly... (or even at all).

Currently I'm using React Router 4 and this is the pattern I'm adopting:

  1. when programmatically leaving the page, I first save current page's state with history.replace(this.state); then I move out of the page with history.push(newLocation)
  2. when a page component is created (componentWillMount) I check for this.props.location.state !== undefined and if so, I restore it with this.setState(this.props.location.state)

My question is: is the above pattern correct? suggested? Is there any better and widely adopted way?

like image 968
nino.porcino Avatar asked Nov 26 '17 11:11

nino.porcino


People also ask

How do you handle back button of browser in React?

Intercept or Handle the Browser's Back Button in React Router. We can listen to back button actions by running the setRouteLeaveHook event for back button actions. } export default withRouter(App);

How do I keep React component state after browser refresh?

To maintain state after a page refresh in React, we can save the state in session storage. const Comp = () => { const [count, setCount] = useState(1); useEffect(() => { setCount(JSON. parse(window. sessionStorage.

How do I go back to initial state React?

Unfortunately, there isn't a built-in way for us to reset the state of the component to its initial state, so we have to extract the initial state into a variable. When you manage state using the useState hook, all you have to do is call your setState function passing it the initial state.


1 Answers

after a while I found a reasonable workaround:

  • in react, after every this.setState() I keep state synchronized with history using window.history.replaceState({ key: history.location.key, state: this.state})
  • when a "page" component is mounted or refreshed (willMount and willReceiveProps) I check for state in props.params.location.state: if there is one, I do restore it; if there is none I create a fresh new state.
  • when navigating on the same page, I do not use routes, I just use this.setState and window.history.pushState
  • when navigating outside of the page, I just use routes and avoid to pass anything in the state

This solution seems to work nicely, the only minor cons are:

  • state must be serializable
  • this.setState is a pitfall because it's asynchronous, you cannot use this.state after it, unless you do trickery.
  • initial empty state must be provided by a function to be used during the restore or init phase, it can't just stay in the constructor() of the Component
  • in Firefox, automatic scroll restoration after the back button works randomly, don't know why, but Chrome and Edge are ok.

Overall I have written a PageComponent that extends Component that does all the init/restoration work; it also overrides this.setState to make it syncs automatically with history and avoids the asynchronous annoyances.

like image 188
nino.porcino Avatar answered Sep 19 '22 14:09

nino.porcino