前言: 最近在做项目时候,遇到了返回时候如果用户没有保存表单,需要拦截路由跳转,并给出提示信息是否要退出。相信做过vue项目的小伙伴都对vue的路由守卫并不陌生,react中如何实现呢?(本分享是针对react-router的v5版本)
一、使用Prompt组件来完成
闲话不多说直接上干货,react-router包里边给我们提供了一个组件,来帮助我们完成路由守卫。它有两个参数when和message。
参数名称 | 类型 | 作用 |
---|---|---|
when | boolean | true 弹窗 false顺利跳转 |
message | function或者字符串 | 函数返回true就顺利跳转,false停止跳转 字符串就弹窗字符串并停止跳转。 |
when值 | message值 | 路由是否跳转 | 是否弹出默认框 |
---|---|---|---|
false | 无论message是函数返回任何值还是message是字符串后边结果都一样 | 是 | 否 |
true | message是字符串 | 否 | 是 |
true | message是函数返回值true | 是 | 否 |
true | message是函数返回值是字符串 | 否 | 是 |
true | message是函数返回false | 否 | 否 |
由于默认弹窗非常不好看,所以,要借助antd或者meet-react来美化弹框。通过上边表格值可知,当when值是true并且message是函数返回值为false时候,才会拦截路由同时,不会弹出默认弹出框。话不多说,直接上实例代码:
import { Dialog } from '@alifd/meet-react';
import React, { useEffect, useState} from 'react';
import { Prompt, useHistory } from 'react-router';
import style from './index.module.scss';
export default function TestPage() {
const history = useHistory();
const [notAllowJump, setNotAllowJump] = useState(true);
/**
* 路由拦截
* @param {*} location string
* @returns boolean
*/
function handleRouter() {
const list = field.getValue('list');
const equal = xxxxx(); // 判断两次值是不是一样
if (equal) {
// 两次值一样,用户没改动数据,直接放行
return true;
}
Dialog.show({
centered: true,
content: '是否保存当前修改数据',
onOk() {
// 用户需要提交,提交后要放行,先将when置为false,再提交操作
setNotAllowJump(false);
xxxxxSubmit(); // 继续提交
},
async onCancel() {
// 用户不提交,直接放弃修改返回上一页。将when置为false再返回,注意setNotAllowJump操作是异步的。
await setNotAllowJump(false);
history.goBack();
},
});
// 用户有修改,返回false拦截跳转,同时屏蔽掉默认弹出框
return false;
}
return (
<div className={style['test-page']}>
<Prompt when={notAllowJump} message={handleRouter} />
<footer>
我是页面内容
</footer>
</div>
);
}
二、使用history.block拦截
block返回值 | 路由是否跳转 | 是否弹出默认框 |
---|---|---|
true | 是 | 否 |
false | 否 | 否 |
string | 否 | 是 |
通过观察返回值不难发现当block返回值是false时候,能够拦截路由跳转,并且不会弹出默认提示框。
import { useHistory } from 'react-router';
import { Dialog } from '@alifd/meet-react';
import React, { useEffect, useState} from 'react';
import style from './index.module.scss';
export default function TestPage() {
const history = useHistory();
useEffect(() => {
history.block(() => {
Dialog.show({
centered: true,
content: '是否保存当前修改数据',
onOk() {
history.block(() => true); // 放开拦截提交操作,成功后在提交函数内跳出去
xxxxxSubmit();
},
async onCancel() {
history.block(() => true);
history.goBack();
},
});
// 开启路由拦截同时阻止默认弹出框
return false;
});
}, [history]);
return (
<div className={style['test-page']}>
<footer>
我是页面内容
</footer>
</div>
);
}