Using React-Router v4/v5 Prompt with custom modal component
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
andaction
the user is attempting to navigate to. Return a string to show a prompt to the user ortrue
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):