我有一个用户可以编辑内容的表单。如果用户有一些未保存的更改并想要离开页面我想给他一个自定义对话框,询问他是否确定。如果那时导航应该继续,并且应该重置表单更改标志,否则用户应该停留在页面上。
在这里,您可以检查我当前正在检查此情况的高阶组件。它正常工作,但函数leave
返回一个字符串,react-router将在本机警报中显示该文本。
有没有办法可以在这里显示我的自定义对话框?我是否也可以获得回调或类似的警报,以便我可以发送一个告诉存储的事件,即最新的更改并不重要。
import React, {Component, PropTypes} from "react";
import connectRouter from "./connectRouter";
import { connect } from "react-redux";
import {injectIntl, intlShape} from "react-intl";
export default function confirmLeave(RouteTargetComponent) {
@injectIntl
@connectRouter
@connect((state, routing) => {
return {
studies: state.studies
};
})
class ConfirmLeaveHOC extends Component { // HOC = Higher Order Component
static propTypes = {
router: PropTypes.object.isRequired,
route: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
intl: intlShape.isRequired,
studies: PropTypes.object.isRequired,
};
leave = () => {
if (this.props.studies.isChanged) {
// lets stop the navigation
return this.props.intl.formatMessage({ id: "confirmLeave" });
}
// continue the navigation
return true;
}
componentDidMount() {
this.props.router.setRouteLeaveHook(this.props.route, this.leave.bind(this));
}
render() {
// render the component that requires auth (passed to this wrapper)
return (<RouteTargetComponent {...this.props}/>);
}
}
return ConfirmLeaveHOC;
}
答案 0 :(得分:3)
由于无法自定义浏览器对话框,因此您必须呈现单独的组件(例如bootstrap模式)并使用回调来确定单击了哪个按钮,以及要采取的操作。
我实际上遇到了你最近遇到的同样问题,我可以使用routerWillLeave
并使用其他组件的回调来解决它。
routerWillLeave = (route) => {
if (!this.waitingForConfirm && this._hasUnsavedChanges() && !this.clickedSave) {
this.refs.confirmAlert._show( ((v) => {
if (v) {
this.context.router.push(route.pathname);
}
this.waitingForConfirm = false;
}).bind(this));
this.waitingForConfirm = true;
return false;
}
}
不幸的是,像这样的自定义对话框的实现非常痛苦。我必须在这里使用3个变量来正确控制所需的行为:
waitingForConfirm
- 在用户确认导航时阻止逻辑再次运行所必需的。具体来说,当回调运行并且我们this.context.router.push(route.pathname)
时,routerWillLeave
将再次运行(!),但由于我们已经确认了导航,我们必须阻止此逻辑再次运行。
_hasUnsavedChanges()
- 检查是否有任何输入字段已更改(没有理由询问是否没有保存更改)。
clickedSave
- 如果用户点击了Save
,请不要要求确认 - 我们知道我们要离开。
_show = (callback) => {
this.callback = callback;
this.setState({show: true});
}
_hide = () => {
this.setState({show: false});
this.callback = null;
}
_dialogAction = (input) => {
if (this.callback) {
this.callback(input);
}
this._hide();
}
render() {
return (
...
<Button onClick={this._dialogAction.bind(this, true)}>Yes</Button>
<Button onClick={this._dialogAction.bind(this, false)}>No</Button>
);
}
显然,您必须自定义上述代码段以适合您的应用程序,但希望它能提供一些有关如何解决问题的见解。
答案 1 :(得分:0)
在组件上使用setRouteLeaveHook是一种不太复杂且更具前瞻性的方法。按照react-router v2.4.0
import React from 'react'
import { withRouter } from 'react-router'
const Page = React.createClass({
componentDidMount() {
this.props.router.setRouteLeaveHook(this.props.route, () => {
if (this.state.unsaved)
return 'You have unsaved information, are you sure you want to
leave this page?'
})
}
render() {
return Stuff
}
})
export default withRouter(Page)