admin管理员组

文章数量:1327135

In react-router v3, I've been using router.setRouteLeaveHook to check if a form has unsaved changes, and if so return false to prevent the transition. Then I would display a custom bootstrap modal dialog with 3 buttons: Save Changes, Discard Changes, and Stay Here.

I can't use react-router v4's Prompt ponent to do this because it's not possible to customize the buttons shown in a browser confirm dialog. It seems like they got rid of any way to cancel the transition in favor of only allowing you to ask the user to approve the transition in a browser confirm dialog.

I tried looking in the code for Prompt but it just passes the dialog message to history, so that doesn't give me any idea how to set up a v3-style route leave hook.

Is it even possible anymore or did the react-router devs intentionally decide to remove this capability this for some reason?

In react-router v3, I've been using router.setRouteLeaveHook to check if a form has unsaved changes, and if so return false to prevent the transition. Then I would display a custom bootstrap modal dialog with 3 buttons: Save Changes, Discard Changes, and Stay Here.

I can't use react-router v4's Prompt ponent to do this because it's not possible to customize the buttons shown in a browser confirm dialog. It seems like they got rid of any way to cancel the transition in favor of only allowing you to ask the user to approve the transition in a browser confirm dialog.

I tried looking in the code for Prompt but it just passes the dialog message to history, so that doesn't give me any idea how to set up a v3-style route leave hook.

Is it even possible anymore or did the react-router devs intentionally decide to remove this capability this for some reason?

Share Improve this question edited Aug 14, 2017 at 12:52 Andy asked Mar 30, 2017 at 15:28 AndyAndy 8,6925 gold badges59 silver badges68 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 3

According to the history package docs, you can replace window.confirm with anything you like:

By default, window.confirm is used to show prompt messages to the user. If you need to override this behavior (or if you're using createMemoryHistory, which doesn't assume a DOM environment), provide a getUserConfirmation function when you create your history object.

So if you want to use your own dialog, something like this should see you through:

const history = createHistory({
  getUserConfirmation(message, callback) {
    showMyCustomDialog(message)
      .then(result => callback(result === 'The YES button'))
  }
})

This means that whatever getUserConfirmation message you set is set for the entire session, but you could abstract it out to your navigation blocking layer that holds additional details for your dialog, e.g. title, button text, colours etc.

Alternatively, you could hijack the message argument and use it for dialog configuration, though that may smell a bit nasty. But it's not a perfect system so anything you do will probably be a bit of a hack.

React Router v4 allows you to pass this method through when you create your router (see here):

<BrowserRouter getUserConfirmation={yourConfirmationFunction} />

Can use Prompt to show custom dialogue. Credit and detailed explanation here.

Prompt requires a message prop, here we can use a custom function for a dialogue and it should return false to prevent navigation.

const BlockingPage = () => {
  const [block, setBlock] = useState(true);
  
  const blockedNavigation = (nLocation) => {
    //nLocation gives the next location object
    
    /**
      * Your custom logic
      *
    **/
    
    //required to block navigation
    return false
  } 

  return(
    <div>
      <Prompt when={block} message={blockedNavigation}/>
    </div>
  )

} 

I don't think this is possible. react-router-v4 uses a package called history that in turns uses the HTML5 history api. The history api only notifies you when you hit the back button (onpopstate), If you think about it this makes lots of sense, since you would not want to give a website the power of not letting you move between pages.

The best you can do is the window onbeforeunload event, that creates a prompt for you asking confirmation from the user, but this is exactly what react-router exposes for you to use.

You might get some of the functionality you want by monkey-patching react-router's internal history object, and that way you can add your own behaviour. But there is a caveat, this is only going to work when you react-router's <Link /> ponent and friends, so you will not be able to intercept refreshes and other things you may want.

If you want to go that route, let me know I can give you some insight or code examples about how might that work and I will update my answer.

本文标签: javascriptreactrouter v4 prevent transition with custom hook instead of PromptStack Overflow