Using React-Router v4/v5 Prompt with custom modal component

Michael Chan
2 min readDec 23, 2018

--

React-Router v4 Prompt on Safari

The Problem

With React-Router v4, we can easily insert route blocking logic into any scene using Prompt, passing only two props: when and message. However, there seem no explicit official docs telling how to implement custom modal instead of the default modal provided by Prompt. This might be okay if your app doesn’t require custom modal UI and 100% localization. Otherwise, the Prompt default modal might not match your requirement since it does not provide props for custom styles and button label text (say I want to implement localized label text .i.e. yes/no). There are other solutions provided in the community using the getUserConfirmation prop of BrowserRouter, which might be hardly implemented inside each scene components independently.

A Simple Solution

In the official docs of ReactRouter/Prompt, the message prop is a function which:

Will be called with the next location and action the user is attempting to navigate to. Return a string to show a prompt to the user or true to allow the transition.

That means when the function returns a string, Prompt will show up, while navigation will be allowed if it returns true.

That has actually not ended. When you tries to return false from the function, what will happen?

Nothing will happen. More accurately, the navigation will be blocked while the default Prompt modal does not show up too.

Gotcha! That means we can hook some logic to show our custom modal before returning false too. We can also check whether we should block the navigation here according to next location and a state telling whether the user has confirmed navigation.

Then our function passed to the message prop can be like this:

handleBlockedRoute = (nextLocation) => {
const {confirmedNavigation} = this.state
const {shouldBlockNavigation} = this.props
if (!confirmedNavigation && shouldBlockNavigation(nextLocation)){
this.showModal(nextLocation)
return false
}

return true
}

The following is the full implementation:

JavaScript and Class version:

Usage:

TypeScript and React 16+ version (Thanks to Roger):

--

--

Michael Chan
Michael Chan

Written by Michael Chan

Based in Hong Kong, a passionate learner and perfectionist, who wants to build something cool with quality.

Responses (27)