kca
kca

Reputation: 6055

Force initial React state when clicking the browsers history back button?

Is there a way to force the initial state on a page (in a component) when the page was reached via the browsers "history back" button ?

Simplest Example:

Now I'd like my page to have it's initial state, not the changed state.

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Try state</title></head>
<body>
    <script>
        // (You can check window.state in the DEV console)
        window.state = 'initial state';
    </script>
    <p id="state-display">static content</p>
    <button onclick="state = 'changed state'; document.getElementById('state-display').innerHTML = state;">change state</button>
</body>
</html>

More specifically

I am changing pages by calling window.location.href = url, and at the same time I set a React state which results in displaying a loading ... info until the new url is loaded.

I would expect, when clicking "back", that the previous page would be loaded with its initial state again, but apparently the browser loads the last state that it has seen when the page was left ?

E.g.

Example:

import React from 'react';
import { createRoot } from 'react-dom/client';

// -- just some test state
const getNextState = (function(){
    const values = [ 'cat', 'dog', 'fish', 'bird', 'kangaroo' ];
    let index = 0;
    return function(){
        const current = index;
        index = index < values.length - 1 ? index + 1 : 0;
        return values[ current ];
    };
})();

// --
function App() {
    const [ state, setState ] = React.useState(() => getNextState() );

    // --
    // can't set state here, because `useEffect` hook is
    // not (always) called when clicking on "back" button
    // --
    React.useEffect(() => {
        console.log('mounted');
    }, []);

    // -- set state and change url
    const goToPage = function( page ){
        setState( '...loading' );
        window.location.href = page;
    };

    return <div>
        <h1>{ window.location.search === '?page2' ? 'Page 2' : 'Page 1' }</h1>
        <p>{ state }</p>
        <button onClick={ () => { goToPage('/?page1'); } }>go to page 1</button>
        <button onClick={ () => { goToPage('/?page2'); } }>go to page 2</button>
        <button onClick={ () => { setState( getNextState() ); } }>change state</button>
    </div>;
}

// --
const root = createRoot(
    document.getElementById('root')!
);

root.render(
  <React.StrictMode>
      <App />
  </React.StrictMode>
);

Note 1): This apparently only happens in a production build (e.g. yarn build, yarn start).

Note 2): Chrome and Firefox seem to behave in the same way here, but this is a simplified example, and in my real app, where I use Redux and NextJs, this problem is only reliably reproducible in Chrome.

Note 3): I'm open for suggestions to change my routing, but note that in some cases I have statically pre-rendered pages and need to do a redirect in a middleware.ts, so I can't just use client side routing.

Approaches that apparently don't work:

Apparently no hooks (like useEffect) are executed when clicking on "history back". Not even the DOMContentLoaded event is fired.

UPDATE:

Apparently this behavior is not consistent. Right now Chrome doesn't show this problem anymore at my computer. Firefox still does.

Upvotes: 0

Views: 148

Answers (0)

Related Questions