我正在尝试使用自定义对话框询问用户确认,然后导航未保存的数据。
关注docs我:
componentDidMount() {
this.props.router.setRouteLeaveHook(
this.props.route,
this.routerWillLeave
)
}
但不是
routerWillLeave(nextLocation) {
if (!this.props.pristine) {
return 'You have unsaved information, are you sure you want to leave this page?'
}
我有
routerWillLeave(nextLocation) {
if (!this.props.pristine) {
this.setState({open: true})
this.forceUpdatate() //necessary or else render won't be called to open dialog
}
我使用的对话框组件来自material-ui,它只需要open
布尔值来控制对话框,它还需要handleCancel
和handleContinue
方法,但我我不确定如何与routerWillLeave
联系起来。
handleCancel
方法很简单,只需关闭对话框:
handleCancel() {
this.setState({open: false})
};
我已将对话框组件包装在名为Notification
export default class Notification extends React.Component {
render() {
const { open, handleCancel, handleContinue } = this.props
const actions = [
<FlatButton
label="Cancel"
primary={true}
onTouchTap={handleCancel}
/>,
<FlatButton
label="Continue"
primary={true}
onTouchTap={handleContinue}
/>,
];
return (
<div>
<Dialog
actions={actions}
modal={false}
open={open}
>
You have unsaved data. Discard changes?
</Dialog>
</div>
);
}
}
我可以从父组件调用它,我在render方法中有这个:
<Notification open={open} handleCancel={this.handleCancel} handleContinue={this.handleContinue}/>
基本上我的问题是如何用routerWillLeave
连接而不是显示本机浏览器警报?
答案 0 :(得分:7)
当您致电createHistory
时,其中一个选项是getUserConfirmation
,其中会提示message
和callback
。对于DOM历史记录(browserHistory
和hashHistory
),getUserConfirmation
调用window.confirm
,将message
传递给它。 callback
函数接收返回值window.confirm
[0]。
您需要做的是提供自己的getUserConfirmation
方法来复制window.confirm
。当它被调用时,你应该显示你的模态并根据点击的按钮触发callback
。
<Notification>
组件应根据用户的操作调用提示message
和callback
函数。
class Notification extends React.Component {
contructor(props) {
this.state = {
open: false
}
}
handleCancel() {
this.props.callback(false)
this.setState({ open: false })
}
handleContinue() {
this.props.callback(true)
this.setState({ open: false })
}
render() {
const { message } = this.props
const { open } = this.state
const actions = [
<FlatButton
label="Cancel"
primary={true}
onTouchTap={this.handleCancel.bind(this)}
/>,
<FlatButton
label="Continue"
primary={true}
onTouchTap={this.handleContinue.bind(this)}
/>,
];
return (
<div>
<Dialog
actions={actions}
modal={true}
open={open}
>
{message}
</Dialog>
</div>
);
}
}
确认模式不是真正您的UI的一部分,这就是为什么我在一个单独的渲染过程中渲染它而不是应用程序的其余部分。
import React from 'react'
import ReactDOM from 'react-dom'
import Notification from './components/Notification'
export default function = (holderID) => {
var modalHolder = document.getElementById(holderID)
return function ModalUserConfirmation(message, callback) {
ReactDOM.render((
<Notification open={true} message={message} callback={callback} />
), modalHolder)
}
}
这显然会迫使您创建自己的历史对象。您不能只导入browserHistory
或hashHistory
,因为它们使用window.confirm
。幸运的是,创建自己的历史是微不足道的。这与browserHistory
[1]中使用的代码基本相同,但它会传递createBrowserHistory
getUserConfirmation
函数。
import createBrowserHistory from 'history/lib/createBrowserHistory'
import createRouterHistory from './createRouterHistory'
export default function(getUserConfirmation) {
return createRouterHistory(createBrowserHistory({
getUserConfirmation
})
}
最后,你需要把它们放在一起。
import createHistory from './createConfirmationHistory'
import ModalConfirmation from './ModalConfirmation'
const getModalConfirmation = ModalConfirmation('modal-holder')
const history = createHistory(getModalConfirmation)
ReactDOM.render((
<Router history={history}>
// ...
</Router>
), document.getElementById('root')
如果你想使用历史单例,你必须重构一下,否则它应该有效。 (不过我实际上没有测试过它。)
[0] https://github.com/mjackson/history/blob/v2.x/modules/DOMUtils.js#L38-L40
[1] https://github.com/ReactTraining/react-router/blob/master/modules/browserHistory.js
答案 1 :(得分:0)
您可以尝试使用react-router-navigation-prompt。
这对我有用。
答案 2 :(得分:0)
我使用Prompt
中的react-router-dom
和antd
中的自定义模式进行了此操作。材质用户界面应具有非常相似的功能。
在index.js
的{{1}}的{{1}}中设置对话框:
getUserConfirmation
然后,您使用其中的元素,如果要尝试导航,则使用Router
道具提供条件以弹出模态。
import { MemoryRouter as Router } from 'react-router-dom'
import { Modal } from 'antd'
import App from './App'
const { confirm } = Modal
const confirmNavigation = (message, callback) => {
confirm({
title: message,
onOk() {
callback(true)
},
onCancel() {
callback(false)
}
})
}
ReactDOM.render(
<Router getUserConfirmation={confirmNavigation}>
<App />
</Router>
document.getElementById('root')
)