如何使用react-router防止路由更改

Mar*_*lec 16 reactjs react-router

我的React应用程序中有一个页面,如果表单很脏,我想阻止用户离开.

在我的react-routes中,我正在使用onLeave prop这样:

<Route path="dependent" component={DependentDetails} onLeave={checkForm}/>
Run Code Online (Sandbox Code Playgroud)

而我的onLeave是:

const checkForm = (nextState, replace, cb) => {
  if (form.IsDirty) {
    console.log('Leaving so soon?');
    // I would like to stay on the same page somehow...
  }
};
Run Code Online (Sandbox Code Playgroud)

有没有办法防止新路由被触发并使用户保持在同一页面上?

Pet*_*des 9

React-router v6 不再支持 Prompt 组件(他们表示希望在有可接受的实现后将其添加回来)。然而,react-router 使用历史包,它提供了以下示例来说明如何阻止转换。

请注意,要真正在 React Router 中实现此功能,您必须用一些黑客技术替换 createBrowserHistory 调用,以确保您使用与 React Router 相同的历史对象(请参见答案底部)。


const history = createBrowserHistory();
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();
  }

Run Code Online (Sandbox Code Playgroud)

您需要将其放入适当的 useEffect 挂钩中,并构建本来由提示提供的其余功能。请注意,如果用户尝试导航离开但关闭选项卡或刷新页面,这也会产生一个(不可自定义的)警告,指示可能不会保存未保存的工作。

请阅读链接页面,因为使用此功能有一些缺点。具体来说,它向 beforeunload 事件添加了一个事件侦听器,这使得页面符合 Firefox 中的 bfcache 的条件(尽管如果导航被取消,代码会尝试取消注册处理程序,但我不确定这是否会恢复可挽救状态)我认为是这些问题这导致react-router禁用Prompt组件。

警告要访问 React Router 6 中的历史记录,您需要按照此处的说明进行操作,这有点黑客攻击。最初,我假设您可以使用 createBrowserHistory 来访问历史对象,因为该代码在 React 路由器文档中进行了说明,但(在我看来有点令人困惑)它只是为了说明历史记录的作用。


MBe*_*mam 8

为时已晚,但是根据React Router Documentation您可以preventing transition<prompt>组件帮助下使用。

  <Prompt
      when={isBlocking}
      message={location =>
        `Are you sure you want to go to ${location.pathname}`
      }
    />
Run Code Online (Sandbox Code Playgroud)

如果isBlocking等于true则显示一条消息。有关更多信息,请阅读文档。


T P*_*ick 6

我认为自从Lazarev的回答以来,推荐的方法已经改变,因为他的链接示例目前不在examples文件夹中.相反,我认为你应该遵循这个例子定义:

componentWillMount() {
  this.props.router.setRouteLeaveHook(
    this.props.route,
    this.routerWillLeave
  )
},
Run Code Online (Sandbox Code Playgroud)

然后定义routerWillLeave为一个返回字符串的函数,该字符串将出现在确认警报中.

UPDATE

之前的链接现已过时且无法使用.在较新版本的React Router中,似乎有一个新组件Prompt可用于取消/控制导航.看这个例子