React Router v4 <Prompt></Prompt>
component非常适合保护导航远离部分填写的表单的用例。
但是如果我们想提供自己的逻辑来代替默认浏览器怎么办 alert()
该组件使用? React 旨在创建 UI,因此它似乎是一个非常合理的用例。在 github 中挖掘有关提示的问题我没有发现有人问这个问题。
有人知道为警报提供自定义行为的解决方案吗?
最佳答案
虽然您可以在阻止通过链接在页面之间导航的同时使用自定义模式组件,但是您无法在尝试关闭浏览器或重新加载时显示自定义模式。
但是,如果您不介意,您可以使用 history.listen
来阻止导航。我为它编写了一个通用 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 };
为了使用上面的内容,您可以简单地提供您的自定义提示模态
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>
关于javascript - React Router v4 Prompt - 覆盖默认警报,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52437195/