【React】React组件卸载生命周期、路由跳转、页面关闭(刷新)拦截提示 [ 前端 ]
晚安月亮 文章 正文

椰奶冻
{{nature("2023-03-05 15:41:18")}}更新需求来源是某页面具有编辑功能,如果用户正在编辑态,且内容还没保存。
如果用户点击了某些地方会导致切换路由,需要弹窗提示是否需要切换。
如果用户想要刷新或关闭浏览器窗口需要提示用户,是否刷新/关闭此网站?
基于这个需求想到了四种方法,记录下来方便自己下次复制粘贴。
1.componentWillUnmount
首先这个钩子函数是在组件卸载前调用的一个函数,它并不能阻止当前组件的卸载。所以不要想方设法在这里做提示,因为即便提示了,组件还是会卸载,文章还是会消失。
2.路由守卫-<Prompt/>
为了实现第一个功能,需要一个跳转路由之前进行的判断。在react-router-dom 4.0
之后取消了先前的路由守卫(其实我没研究过之前版本的,这个描述摘自网络)。在react-router-dom 4.0
之后,实现这个功能可以依靠<Prompt/>
组件。文档链接↗
把这个组件添加到你的文章编辑页组件的任意部分
import {Prompt} from 'react-router-dom';
const Editor=()=>{
return (
<div>
<Prompt
when={true}
message={location => '文章要保存吼,确定离开吗?'}
/>
</div>
)
}
这里有一点需要注意,使用<Prompt/>
时,你的路由跳转必须通过<Link/>
实现,而不能依靠<a/>
原生标签。
点击取消时就会留在当前页面。至此已经实现了路由跳转时提醒用户进行保存的功能。
3.history.block
const history = useHistory();
const releaseRef = useRef(() => {});
const confirmRef = useRef<{
destroy(): void;
} | null>();
let ref = useRef<any>(show);
ref.current = show;
// 切换页面拦截提醒
useEffect(() => {
let releaseBlock = history.block((location, action) => {
if (ref.current) {
confirmRef.current?.destroy();
confirmRef.current = Modal.confirm({
title: '是否离开当前页面?',
content: '当前正在编辑的内容将不会保存',
onOk: () => {
releaseBlock();
if (action === 'PUSH') {
history.push(location);
} else if (action === 'POP') {
history.goBack();
} else {
history.replace(location);
}
},
onCancel: () => {
confirmRef.current?.destroy();
return false;
},
});
return false;
}
});
return () => {};
}, []);
4.窗口关闭事件-beforeunload
实现第二个功能需要依靠对窗口的监听。React应用中对于窗口事件的应用远没有DOM事件频繁,所以好久没碰到还是有点手生的。最关键的就是,应该在何时进行监听?
应该在组件挂载时监听事件,组件卸载时移除事件监听。因为我已经开始全面采用hooks
新特性了,所以这里使用到useEffect
。
// 关闭页面拦截
useEffect(() => {
if (show) {
const handleBeforeUnload = (e: any) => {
e.preventDefault();
// // 这里没用,浏览器弹窗提示不能自定义
e.returnValue = '你确定离开此页面吗';
return e.returnValue;
};
window.addEventListener('beforeunload', handleBeforeUnload);
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
};
}
}, [show]);
这里有几个需要注意的地方:
useEffect
第二个参数为空数组,表示只调用了componentDidMount
和componentWillUnmount
两个钩子- 事件监听和移除的第二个参数为同一个事件处理函数
- 在
beforeunload
事件中的confirm
,prompt
,alert
会被忽略。取而代之的是一个浏览器内置的对话框。(参考:MDN|beforeunload) - 必须要有
returnValue
且为非空字符串,但是在某些浏览器中这个值并不会作为弹窗信息
{{nature('2022-06-23 23:10:58')}} {{format('1473')}}人已阅读
{{nature('2023-02-03 16:12:08')}} {{format('1390')}}人已阅读
{{nature('2024-05-29 15:14:38')}} {{format('1012')}}人已阅读
{{nature('2024-05-24 15:20:21')}} {{format('897')}}人已阅读
目录
标签云
一言
评论 0
{{userInfo.data?.nickname}}
{{userInfo.data?.email}}