提问者:小点点

检测用户使用反应路由器离开页面


我希望我的 ReactJS 应用程序在离开特定页面时通知用户。特别是提醒他/她执行操作的弹出消息:

"更改已保存,但尚未发布。现在就做吗?”

我是应该在< code>react-router上全局触发此操作,还是可以在react页面/组件中完成此操作?

我在后者上没有发现任何东西,我宁愿避免第一个。当然,除非这是常态,但这让我想知道如何在不向用户可以访问的所有其他可能页面添加代码的情况下做这样的事情…

欢迎有任何见解,谢谢!


共3个答案

匿名用户

react routerv4引入了一种使用Prompt阻止导航的新方法。只需将其添加到要阻止的组件:

import { Prompt } from 'react-router'

const MyComponent = () => (
  <>
    <Prompt
      when={shouldBlockNavigation}
      message='You have unsaved changes, are you sure you want to leave?'
    />
    {/* Component JSX */}
  </>
)

这将阻止任何路由,但不会刷新或关闭页面。要阻止这种情况,您需要添加以下内容(根据需要使用适当的React生命周期进行更新):

componentDidUpdate = () => {
  if (shouldBlockNavigation) {
    window.onbeforeunload = () => true
  } else {
    window.onbeforeunload = undefined
  }
}

onbeforeunload具有浏览器的各种支持。

匿名用户

在 react-router v2.4.0 或更高版本以及 v4 之前,有几个选项

  1. 路由添加
  2. 功能
 <Route
      path="/home"
      onEnter={ auth }
      onLeave={ showConfirm }
      component={ Home }
    >
    

您可以阻止过渡发生或在使用左钩离开路径之前提示用户。

const Home = withRouter(
  React.createClass({

    componentDidMount() {
      this.props.router.setRouteLeaveHook(this.props.route, this.routerWillLeave)
    },

    routerWillLeave(nextLocation) {
      // return false to prevent a transition w/o prompting the user,
      // or return a string to allow the user to decide:
      // return `null` or nothing to let other hooks to be executed
      //
      // NOTE: if you return true, other hooks will not be executed!
      if (!this.state.isSaved)
        return 'Your work is not saved! Are you sure you want to leave?'
    },

    // ...

  })
)

请注意,此示例使用了< code>v2.4.0.中引入的< code>withRouter高阶组件

但是,手动更改URL中的路由时,这些解决方案并不能完美运行

从某种意义上说,

    < li >我们看到确认- ok < li >页面的容器不重新加载-正常 < li>URL没有改变-不正常

对于react-router v4使用提示或自定义历史记录:

然而,在< code>react-router v4中,借助来自“react-router”的< code >提示符,实现起来要容易得多

根据留档

提示

用于在导航离开页面之前提示用户。当您的应用程序进入一个应该阻止用户离开的状态时(如表单填写一半),呈现一个<code>

import { Prompt } from 'react-router'

<Prompt
  when={formIsHalfFilledOut}
  message="Are you sure you want to leave?"
/>

消息:字符串

当用户尝试导航离开时提示用户的消息。

<Prompt message="Are you sure you want to leave?"/>

消息:func

将与用户尝试导航到的下一个位置和操作一起调用。返回一个字符串以向用户显示提示或true以允许转换。

<Prompt message={location => (
  `Are you sure you want to go to ${location.pathname}?`
)}/>

时间:bool

而不是有条件地呈现< code >

在你的渲染方法中,你只需要根据你的需要在文档中添加这个。

更新:

如果您希望在用户离开页面时采取自定义操作,您可以利用自定义历史记录并配置您的路由器,如下所示

历史.js

import createBrowserHistory from 'history/createBrowserHistory'
export const history = createBrowserHistory()

... 
import { history } from 'path/to/history';
<Router history={history}>
  <App/>
</Router>

然后在您的组件中,您可以使用 history.block

import { history } from 'path/to/history';
class MyComponent extends React.Component {
   componentDidMount() {
      this.unblock = history.block(targetLocation => {
           // take your action here     
           return false;
      });
   }
   componentWillUnmount() {
      this.unblock();
   }
   render() {
      //component render here
   }
}

匿名用户

对于react-router2.4.0

注意:建议将所有代码迁移到最新的react-router以获得所有新的好东西。

正如反应路由器文档中所建议的:

应该使用< code>withRouter高阶组件:

我们认为这个新的HoC更好,更容易,并将在文档和示例中使用它,但切换并不是一个硬性要求。

作为文档中的ES6示例:

import React from 'react'
import { withRouter } from 'react-router'

const Page = React.createClass({

  componentDidMount() {
    this.props.router.setRouteLeaveHook(this.props.route, () => {
      if (this.state.unsaved)
        return 'You have unsaved information, are you sure you want to leave this page?'
    })
  }

  render() {
    return <div>Stuff</div>
  }

})

export default withRouter(Page)