5

I've learned that with react-router-dom v5 it was possible to use the <Prompt> component in order to ask the user before a page transition happens, so that the user can prevent it.

Now, for the time being, they removed it from v6 (planning to have a robust implementation "sometime later"). Instead, they recommended to implement an equivalent component by yourself ... which I would like to do now.

But: I've found no way to actually prevent the page transition in react-router-dom v6. Does anyone know anything about it?

devnull69
  • 16,402
  • 8
  • 50
  • 61

1 Answers1

4

You can but it requires using a custom history object and HistoryRouter. For this history@5 needs to be a package dependency.

  1. Import version 5 of history.

    npm i -S history@5
    
  2. Create and export a custom history object.

    import { createBrowserHistory } from 'history';
    
    export default createBrowserHistory();
    
  3. Import and render a HistoryRouter and pass history as a prop.

    ...
    import { unstable_HistoryRouter as Router } from "react-router-dom";
    import history from './history';
    ...
    
    <Router history={history}>
      <App />
    </Router>
    
  4. Follow the docs for blocking transitions.

    // Block navigation and register a callback that
    // fires when a navigation attempt is blocked.
    let unblock = history.block((tx) => {
      // Navigation was blocked! Let's show a confirmation dialog
      // so the user can decide if they actually want to navigate
      // away and discard changes they've made in the current page.
      let url = tx.location.pathname;
      if (window.confirm(`Are you sure you want to go to ${url}?`)) {
        // Unblock the navigation.
        unblock();
    
        // Retry the transition.
        tx.retry();
      }
    });
    

Demo:

Edit agitated-blackwell-dpl9b3

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • but how "safe" is to use unstable_HistoryRouter? – stackoverflow Feb 09 '23 at 08:17
  • @stackoverflow Unless I'm misunderstanding your question it's safe and available up through at least RRDv6.7. It's "unstable" *not* "unsafe". My answer [here](https://stackoverflow.com/a/70000286/8690857) has a bit more detail regarding the history router. I'll test my linked sandbox here though as a sanity check. – Drew Reese Feb 09 '23 at 08:18
  • @stackoverflow Just verified, it's working with the latest RRDv6.8.1. – Drew Reese Feb 09 '23 at 08:21
  • I was mostly curious about other "side effects" regarding the browser state, not whether it's working with RRD6+ or not, obiously will work, but being an "unsafe" API, I guess there are some reasons why not might be a great idea to use in in prod – stackoverflow Feb 09 '23 at 08:23
  • 1
    @stackoverflow Like I said, it's not necessarily "unsafe", it's just unstable, meaning it can be pulled from the library at any moment. It's been there and available since v6.3 or so, and in my linked answer is the next *workaround* if you have started using the new Data APIs and routers. It's stable-ish, but I understand your hesitation. If there's concern about it then obviously you shouldn't use it in production if you don't want to be caught off-guard on a future update. – Drew Reese Feb 09 '23 at 08:28
  • sorry for late response, I just tried to use this solution with latest history and react router but I got a TS erorr Type 'BrowserHistory' is missing the following properties from type 'History': createURL, encodeLocationts(2739) I've checked the types from both packages and seems that react router is having two new methods on the API: createURL & encodeLocationts, which history API is lacking Are you aware of this issue, is there a workaround? Should I downgrade react-router to something older? like 6.2? – stackoverflow Feb 09 '23 at 10:15
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/251752/discussion-between-drew-reese-and-stackoverflow). – Drew Reese Feb 09 '23 at 10:19