6

How do I disable a browser back button click from user using react-router-dom v4?

I am showing a modal on a page and when the user presses browser back button then the user is taken to the previous screen, instead I want to simply close the modal.

I tried doing this

onBackButtonEvent(event) {
    event.preventDefault();  
    // the user shouldn't be able to move backward or forward  
}
componentDidMount() {
    window.onpopstate = this.onBackButtonEvent;
}

But this doesn't prevent the user from going backward or forward. Is there a way to handle this via react-router-dom?

I have tried multiple solutions but nothing seems to work.

Singh
  • 1,887
  • 3
  • 18
  • 29
  • There is no way you could fit your modal into a new route, e.g. `/myroute/edit`, and when the user clicks the back button he gets taken to `/myroute` and the modal is closed automatically? – Tholle Jul 17 '18 at 12:16
  • But this is exactly what I want to avoid, I don't want to create new route. I mean, a modal isn't supposed to have a different route, right? – Singh Jul 17 '18 at 12:26
  • I don't see why not. – Tholle Jul 17 '18 at 12:26
  • Okay. What if the modal has a transparent background and I want to show the user the same background when the modal is active? How do I render the new modal on top of the current route just so that the user has a feel that they haven't left the current route? – Singh Jul 17 '18 at 12:28
  • Just put it outside of the `Switch` so `/myroute` and `/myroute/edit` can be rendered at the same time. – Tholle Jul 17 '18 at 12:29
  • 1
    Okay. I will try that. – Singh Jul 17 '18 at 12:29
  • 1
    [I created a simple example maybe you can use for inspiration](https://codesandbox.io/s/3x534mkz5p) – Tholle Jul 17 '18 at 12:48
  • Did my answer work for you? – Tholle Jul 18 '18 at 13:55
  • It certainly did in a way. There is one problem with this approach. The content inside ModalComponent is dynamic not limited to variable but the JSX itself. And the content depends upon from where the ModalComponent is called. This is why I wanted to disable back button in the first place and render the ModalComponent from within other Parent Component so I could fill the contents inside the Modal from the Parent and then read it via this.props.children. I hope that makes senses. – Singh Jul 19 '18 at 02:07
  • Alright. I updated the answer. – Tholle Jul 19 '18 at 11:17
  • You can check this answer https://stackoverflow.com/a/72475147/4574879 – Aryan Moradi Jun 02 '22 at 11:45

2 Answers2

6

I know this question's a little old but I stumbled on it while looking for the answer myself. There's no clean way to "disable" the back button but to enable the user to only close the modal when clicking the browser back button I found this to work.

Simply pass the history to your modal component in props and call the below on the componentWillUnmount function.

componentWillUnmount() {
    this.props.history.goForward();
}

This will seamlessly force the browser to stay on the same page but close the modal (assuming it's a class component).

UPDATE: If using functional components, the above componentWillUnmount function looks like the hook below.

React.useEffect(() => {
    return () => {
            props.history.goForward();
        }
    }, []);
James Morrison
  • 1,954
  • 2
  • 21
  • 48
4

You could create a new Route for your modal and keep it outside of your Switch. This way regular navigation will still apply, and you can also render the modal on top of what is rendered in your Switch.

Example

function Home() {
  return <div> Home </div>;
}

function MyRoute() {
  return (
    <div>
      <h1>MyRoute</h1>
      <Link to="/myroute/edit"> Edit </Link>
      <Route
        path="/myroute/edit"
        render={({ history }) => (
          <ModalComponent history={history}>
            Welcome to the MyRoute edit screen
          </ModalComponent>
        )}
      />
    </div>
  );
}

class ModalComponent extends React.Component {
  onClick = e => {
    e.preventDefault();
    this.props.history.goBack();
  };

  render() {
    return (
      <Modal isOpen>
        <h1> {this.props.children} </h1>
        <Link to="/myroute" onClick={this.onClick}>
          Back
        </Link>
      </Modal>
    );
  }
}

function App() {
  return (
    <BrowserRouter>
      <div>
        <Link to="/"> Home </Link>
        <Link to="/myroute"> My Route </Link>
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/myroute" component={MyRoute} />
        </Switch>
      </div>
    </BrowserRouter>
  );
}

const rootElement = document.getElementById("root");
Modal.setAppElement(rootElement);
ReactDOM.render(<App />, rootElement);
Tholle
  • 108,070
  • 19
  • 198
  • 189
  • I implemented this and it gives me error saying `TypeError: Cannot read property 'props' of undefined` , when I press the button. – Maifee Ul Asad Aug 31 '19 at 13:25