Хотя вы можете использовать пользовательский модальный компонент, предотвращая переход между страницами по ссылкам, вы не можете отобразить пользовательский модал при попытке закрыть браузер или перезагрузить его.
Однако, если вас это устраивает, вы можете использовать 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
// /205361/kak-ya-mogu-pereopredelit-dialog-onbeforeunload-i-zamenit-ego-svoim-sobstvennym
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>