Javascript ReactRouter v4提示符-覆盖默认警报
React Router v4Javascript ReactRouter v4提示符-覆盖默认警报,javascript,reactjs,react-router,Javascript,Reactjs,React Router,React Router v4非常适合于保护导航远离部分填写表单的用例 但是,如果我们想提供自己的逻辑来代替此组件使用的默认浏览器alert(),该怎么办?React旨在创建UI,因此它看起来是一个非常合理的用例。我在网上浏览了一下Prompt上的问题,没有发现有人问这个问题 有人知道为警报提供自定义行为的解决方案吗?尽管您可以使用自定义模式组件,同时防止通过链接在页面之间导航,但在尝试关闭浏览器或重新加载时,无法显示自定义模式。 但是,如果您觉得没问题,您可以利用历史记录。收听并阻止导航。我为
非常适合于保护导航远离部分填写表单的用例
但是,如果我们想提供自己的逻辑来代替此组件使用的默认浏览器alert()
,该怎么办?React旨在创建UI,因此它看起来是一个非常合理的用例。我在网上浏览了一下Prompt上的问题,没有发现有人问这个问题
有人知道为警报提供自定义行为的解决方案吗?尽管您可以使用自定义模式组件,同时防止通过链接在页面之间导航,但在尝试关闭浏览器或重新加载时,无法显示自定义模式。 但是,如果您觉得没问题,您可以利用
历史记录。收听并阻止导航。我为它编写了一个通用的HOC,它解决了这个用例
在下面的代码中,白名单中的路径名是您希望其他人在不显示提示的情况下导航到的路径名
import React from 'react';
import { withRouter } from 'react-router';
import _ from 'lodash';
const navigationPromptFactory = ({ Prompt }) => {
const initialState = {
currentLocation: null,
targetLocation: null,
isOpen: false
};
class NavigationPrompt extends React.Component {
static defaultProps = {
when: true
};
state = initialState;
componentDidMount() {
this.block(this.props);
window.addEventListener('beforeunload', this.onBeforeUnload);
}
componentWillReceiveProps(nextProps) {
const {
when: nextWhen,
history: nextHistory,
whiteListedPathnames: nextWhiteListedPaths
} = nextProps;
const { when, history, whiteListedPathnames } = this.props;
if (
when !== nextWhen ||
!_.isEqual(nextHistory.location, history.location) ||
!_.isEqual(whiteListedPathnames, nextWhiteListedPaths)
) {
this.unblock();
this.block(nextProps);
}
}
componentWillUnmount() {
this.unblock();
window.removeEventListener('beforeunload', this.onBeforeUnload);
}
onBeforeUnload = e => {
const { when } = this.props;
// we can't override an onBeforeUnload dialog
// eslint-disable-next-line
// https://stackoverflow.com/questions/276660/how-can-i-override-the-onbeforeunload-dialog-and-replace-it-with-my-own
if (when) {
// support for custom message is no longer there
// https://www.chromestatus.com/feature/5349061406228480
// eslint-disable-next-line
// https://stackoverflow.com/questions/38879742/is-it-possible-to-display-a-custom-message-in-the-beforeunload-popup
// setting e.returnValue = "false" to show prompt, reference below
//https://github.com/electron/electron/issues/2481
e.returnValue = 'false';
}
};
block = props => {
const {
history,
when,
whiteListedPathnames = [],
searchQueryCheck = false
} = props;
this.unblock = history.block(targetLocation => {
const hasPathnameChanged =
history.location.pathname !== targetLocation.pathname;
const hasSearchQueryChanged =
history.location.search !== targetLocation.search;
const hasUrlChanged = searchQueryCheck
? hasPathnameChanged || hasSearchQueryChanged
: hasPathnameChanged;
const isTargetWhiteListed = whiteListedPathnames.includes(
targetLocation.pathname
);
const hasChanged =
when && hasUrlChanged && !isTargetWhiteListed;
if (hasChanged) {
this.setState({
currentLocation: history.location,
targetLocation,
isOpen: true
});
}
return !hasChanged;
});
};
onConfirm = () => {
const { history } = this.props;
const { currentLocation, targetLocation } = this.state;
this.unblock();
// replacing current location and then pushing navigates to the target otherwise not
// this is needed when the user tries to change the url manually
history.replace(currentLocation);
history.push(targetLocation);
this.setState(initialState);
};
onCancel = () => {
const { currentLocation } = this.state;
this.setState(initialState);
// Replacing the current location in case the user tried to change the url manually
this.unblock();
this.props.history.replace(currentLocation);
this.block(this.props);
};
render() {
return (
<Prompt
{...this.props}
isOpen={this.state.isOpen}
onCancel={this.onCancel}
onConfirm={this.onConfirm}
/>
);
}
}
return withRouter(NavigationPrompt);
};
export { navigationPromptFactory };
从“React”导入React;
从“react router”导入{withRouter};
从“lodash”进口;
常量navigationPromptFactory=({Prompt})=>{
常量初始状态={
当前位置:空,
targetLocation:null,
伊索彭:错
};
类NavigationPrompt扩展了React.Component{
静态defaultProps={
时间:对
};
状态=初始状态;
componentDidMount(){
this.block(this.props);
window.addEventListener('beforeunload',this.onBeforeUnload);
}
组件将接收道具(下一步){
常数{
时间:下一次,
历史:下一个历史,
白名单路径名称:下一个白名单路径
}=下一步;
const{when,history,whiteListedPathnames}=this.props;
如果(
何时!==nextWhen||
!\ isEqual(nextHistory.location,history.location)||
!\ isEqual(白名单路径名,下一个白名单路径)
) {
这是unblock();
这个.块(下一步);
}
}
组件将卸载(){
这是unblock();
window.removeEventListener('beforeunload',this.onBeforeUnload);
}
onBeforeUnload=e=>{
const{when}=this.props;
//我们无法覆盖onBeforeUnload对话框
//eslint禁用下一行
// https://stackoverflow.com/questions/276660/how-can-i-override-the-onbeforeunload-dialog-and-replace-it-with-my-own
如果(何时){
//不再支持自定义消息
// https://www.chromestatus.com/feature/5349061406228480
//eslint禁用下一行
// https://stackoverflow.com/questions/38879742/is-it-possible-to-display-a-custom-message-in-the-beforeunload-popup
//设置e.returnValue=“false”以显示提示,请参考下文
//https://github.com/electron/electron/issues/2481
e、 returnValue='false';
}
};
块=道具=>{
常数{
历史
什么时候
whiteListedPathnames=[],
searchQueryCheck=false
}=道具;
this.unblock=history.block(targetLocation=>{
常量haspathname已更改=
history.location.pathname!==targetLocation.pathname;
const hasSearchQueryChanged=
history.location.search!==targetLocation.search;
const hasUrlChanged=searchQueryCheck
?HasPathName已更改| | hasSearchQueryChanged
:haspathname已更改;
const isTargetWhiteListed=whiteListedPathnames.includes(
targetLocation.pathname
);
常数改变了=
当&&hasUrlChanged&&!IsTargetWhiteList;
如果(已更改){
这是我的国家({
当前位置:history.location,
目标定位,
伊索彭:是的
});
}
回来!改变了;
});
};
onConfirm=()=>{
const{history}=this.props;
const{currentLocation,targetLocation}=this.state;
这是unblock();
//替换当前位置,然后按导航键导航到目标位置,否则不会
//当用户试图手动更改url时,这是必需的
历史。替换(当前位置);
历史。推送(目标定位);
此.setState(初始状态);
};
onCancel=()=>{
const{currentLocation}=this.state;
此.setState(初始状态);
//如果用户试图手动更改url,请替换当前位置
这是unblock();
this.props.history.replace(当前位置);
this.block(this.props);
};
render(){
返回(
);
}
}
使用路由器返回(导航提示);
};
导出{navigationPromptFactory};
为了使用上述功能,您只需提供自定义提示模式,如
const NavigationPrompt = navigationPromptFactory({
Prompt: AlertDialog
});
const whiteListedPathnames = [`${match.url}/abc`, match.url];
<NavigationPrompt
when={isEditingPlan}
cancelLabel={'Stay'}
confirmLabel={'Leave'}
whiteListedPathnames={whiteListedPathnames}
title={'Leave This Page'}
>
<span>
Unsaved Changes may not be saved
</span>
</NavigationPrompt>
const NavigationPrompt=navigationPromptFactory({
提示:AlertDialog
});
const whiteListedPathnames=[`${match.url}/abc`,match.url];
无法保存未保存的更改
默认情况下,提示组件不允许覆盖window.alert()的使用
这里有一个与您的需求相匹配的对话链接
import { useEffect, useRef } from 'react';
import { useHistory } from 'react-router-dom';
interface IProps {
when: boolean;
message: string;
}
export default function RouteLeavingGuard({ when, message }: IProps) {
const history = useHistory();
const lastPathName = useRef(history.location.pathname);
useEffect(() => {
const unlisten = history.listen(({ pathname }) => lastPathName.current = pathname);
const unblock = history.block(({ pathname }) => {
if (lastPathName.current !== pathname && when) {
return message;
}
});
return () => {
unlisten();
unblock();
}
}, [history, when, message]);
return null;
}