React组件卸载、路由跳转、页面关闭(刷新)以前进行提示

React组件卸载生命周期、路由跳转和页面关闭三者看起来有些相似的地方,好比都是当前组件即将从视口消失,但实际上所触发的事件均不相同。以一个实际案例出发:react

某单页应用的 文章编辑页用户正在编辑文章,此时还没有保存。

当用户不当心要跳转到另一个路由时须要提醒用户是否继续跳转,这个过程须要触发路由跳转以及组件卸载api

而用户不当心点了关闭标签页按钮,或刷新了页面。这个过程触发了页面卸载事件;数组

在这个案例中咱们须要实现:浏览器

1. 用户跳转页面时弹出提示框(路由采用histroy模式)网络

2. 用户关闭页面时弹出提示框react-router

componentWillUnmount

首先这个钩子函数是在组件卸载前调用的一个函数,它并不能阻止当前组件的卸载。因此不要千方百计在这里作提示,由于即使提示了,组件仍是会卸载,文章仍是会消失。dom

路由守卫-<Prompt/>

为了实现第一个功能,须要一个跳转路由以前进行的判断。在react-router-dom 4.0 以后取消了先前的路由守卫(其实我没研究过以前版本的,这个描述摘自网络)。在react-router-dom 4.0以后,实现这个功能能够依靠<Prompt/>组件。文档连接↗函数

把这个组件添加到你的文章编辑页组件的任意部分code

import {Prompt} from 'react-router-dom';
const Editor=()=>{
    return (
        <div>
          <Prompt
            when={true}
            message={location => '文章要保存吼,肯定离开吗?'}
          />
        </div>
    )
}

这里有一点须要注意,使用<Prompt/>时,你的路由跳转必须经过<Link/>实现,而不能依靠<a/>原生标签。
点击取消时就会留在当前页面。至此已经实现了路由跳转时提醒用户进行保存的功能。component

窗口关闭事件-beforeunload

实现第二个功能须要依靠对窗口的监听。React应用中对于窗口事件的应用远没有DOM事件频繁,因此很久没碰到仍是有点手生的。最关键的就是,应该在什么时候进行监听?

应该在组件挂载时监听事件,组件卸载时移除事件监听。由于我已经开始全面采用hooks新特性了,因此这里使用到useEffect

import React,{useEffect} from 'react';

const Editor=()=>{

 //监听窗口事件
    useEffect(() => {
        const listener = ev => {
            ev.preventDefault();
            ev.returnValue='文章要保存吼,肯定离开吗?';
        };
        window.addEventListener('beforeunload', listener);
        return () => {
            window.removeEventListener('beforeunload', listener)
        }
    }, []);
    
//return ...
}

这里有几个须要注意的地方:

  1. useEffect第二个参数为空数组,表示只调用了componentDidMountcomponentWillUnmount两个钩子
  2. 事件监听和移除的第二个参数为同一个事件处理函数
  3. beforeunload事件中的confirmpromptalert会被忽略。取而代之的是一个浏览器内置的对话框。(参考:MDN|beforeunload
  4. 必需要有returnValue且为非空字符串,可是在某些浏览器中这个值并不会做为弹窗信息
相关文章
相关标签/搜索