使用React实现浏览器的返回按钮

10

我正在使用React。当用户点击返回按钮时,我希望警告用户。

我已经做的是

handleWindowClose = (ev) => {
    ev.preventDefault();
    return ev.returnValue = 'Leaving this page will loose data';
}

componentDidMount = () => {
    window.addEventListener('beforeunload',this.handleWindowClose);
}

componentWillUnmount = () => {
    window.removeEventListener('beforeunload',this.handleWindowClose);
}

但是,这在点击后退按钮时不起作用。所以我尝试了以下做法:

handleWindowClose = (ev) => {
    ev.preventDefault();
    return ev.returnValue = 'Leaving this page will loose data';
}

onBackButtonEvent = (e) => {
    e.preventDefault();
    if (confirm("Do you want to loose this data")) {
        window.history.go(0);
    }
    else {
        window.history.forward();
    }
}

componentDidMount = () => {
    window.addEventListener('beforeunload',this.handleWindowClose);
    window.addEventListener('popstate',this.onBackButtonEvent);
}

componentWillUnmount = () => {
    window.removeEventListener('beforeunload',this.handleWindowClose);
    window.removeEventListener('popstate',this.onBackButtonEvent);
}

我没有使用react-router。是否有更好的方法只使用React来完成此操作?同时,我希望窗口停留在该页面,而不使用history.forward(),因为这将导致窗口状态丢失。


有什么不想使用 react-router 的好理由吗? - U r s u s
4个回答

7

在处理React中的后退按钮时,我遇到了以下问题:

  1. 第一次时没有调用popstate事件。
  2. 在执行我的自定义后退逻辑后,它被调用了两次。

为了解决问题1,我编写了以下代码:

componentDidMount() {
    window.history.pushState(null, null, window.location.pathname);
    window.addEventListener('popstate', this.onBackButtonEvent);
}

为了解决问题2,我编写了以下代码:
onBackButtonEvent = (e) => {
    e.preventDefault();

    if (!this.isBackButtonClicked) {
        if (window.confirm("Do you want to save your changes")) {
            this.isBackButtonClicked = true;
            // Your custom logic to page transition, like react-router-dom history.push()
        }
        else {
            window.history.pushState(null, null, window.location.pathname);
            this.isBackButtonClicked = false;
        }
    }
}

不要忘记在构造函数中添加this.isBackButtonClicked = false;并取消订阅事件。
componentWillUnmount = () => {
    window.removeEventListener('popstate', this.onBackButtonEvent);
}

4
我遇到过类似的问题,并通过以下方式进行修复:
componentDidUpdate(){
  
    window.onpopstate  = (e) => {
        // Tour code...
    }      
}

1
此外,您可以在这里找到浏览器支持的详细信息和简单示例。 - alpay

1
看起来你需要的是 onbeforeunload 事件:查看这个 相关问题,其中包含一个 有用的演示
此外,MDN 文档 中也包含一个有用的示例。
假设您有不想使用react-router的充分理由,我将概述使用JavaScript的方法。
看起来您捕获了错误的事件。您需要获取URL哈希的任何更改,因此应该使用onhashchange
文档中的示例:
if ("onhashchange" in window) {
    alert("The browser supports the hashchange event!");
}

function locationHashChanged() {
    if (location.hash === "#somecoolfeature") {
        somecoolfeature();
    }
}

window.onhashchange = locationHashChanged;

然而,考虑到您正在开发React应用程序,我建议尝试使用react-router。在这种情况下,browserHistory将成为您的好帮手。


我没有进行路由。我有一个向导式的应用程序,用户点击下一步时,我使用ajax获取下一个数据。因此,这不会在浏览器历史记录中注册。但是,当用户单击“返回”按钮时,应用程序会将其从向导中带出。因此,我无法使用hashChange。因此,我没有窗口状态。因此,即使我使用history.forward,我也会有一个新状态并失去那个状态。因此,如果有一些优雅的方法可以做到这一点,就像浏览器关闭事件一样。 - dhrDatt
使用react-router...??由于应用程序已经构建,现在也不可能选择这个选项。 - dhrDatt
似乎对我没有帮助。就像我之前提到过的,我已经使用了这个事件。这个事件不会在后退按钮上触发,只有在刷新和关闭窗口事件上才会触发。 - dhrDatt
我没有看到你提到 onbeforeunload。你使用的是不同的 beforeunload。而且,你错了:onbeforeunload确实会在点击后退按钮时触发。你有实际检查过我在编辑中链接的演示吗?@dhrDatt - U r s u s
我使用了这个 window.addEventListener('onbeforeunload',this.handleWindowClose);handleWindowClose = (ev) => { ev.preventDefault(); return ev.returnValue = '离开此页面将会丢失数据'; } - dhrDatt
显示剩余2条评论

1

Try this code:

componentDidMount() {
    window.addEventListener("popstate", this.onBackButtonEvent)
}

componentWillUnmount() {
  window.removeEventListener("popstate", this.onBackButtonEvent)
}

onBackButtonEvent = () => {
    window.history.forward()
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接