使用SetRouteleavehook使用自定义对话框确认导航



我正在尝试使用自定义对话框要求用户进行确认,然后再浏览未保存的数据。

遵循我拥有的文档:

  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
    }

我正在使用的对话框组件来自材料-UI,它只是期望open布尔值控制对话框,它也采用handleCancelhandleContinue方法,但我不确定如何与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>
    );
  }
}

,我可以从父组件中调用它,我在渲染方法中使用了此内容:

<Notification open={open} handleCancel={this.handleCancel} handleContinue={this.handleContinue}/>

基本上我的问题是如何将其与routerWillLeave进行连接,而不是显示本机浏览器警报?

调用createHistory时,它的选项之一是getUserConfirmation,它采用提示messagecallback。对于DOM历史记录(browserHistoryhashHistory),getUserConfirmation调用window.confirm,将其传递给messagecallback功能接收window.confirm [0]的返回值。

您需要做的是提供复制window.confirmgetUserConfirmation方法。调用时,您应该显示模式并根据单击哪个按钮触发callback

Notification.js

<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>
    );
  }
}

modalConfirmation.js

确认模式不是真正的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)
  }
}

这显然会迫使您创建自己的历史对象。您不能仅导入browserHistoryhashHistory,因为使用window.confirm。幸运的是,创建自己的历史是微不足道的。这本质上是与browserHistory [1]中使用的代码相同的代码,但是它通过createBrowserHistory您的getUserConfirmation函数。

createConfirmationhishory.js

import createBrowserHistory from 'history/lib/createBrowserHistory'
import createRouterHistory from './createRouterHistory'
export default function(getUserConfirmation) {
  return createRouterHistory(createBrowserHistory({
    getUserConfirmation
  })
}

index.js

最后,您需要将所有这些放在一起。

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/reaecttraining/react-router/blob/master/modules/browserhistory.js

您可以尝试使用React-Router-Navigation-Prompt。

这对我有用。

i使用react-router-domPrompt使用antd的自定义模式进行了此操作。材料UI应该具有非常相似的功能。

在我的index.js中,我在RoutergetUserConfirmation中设置了对话框:

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')
)

然后,如果您尝试走开导航,则在其中使用要提示的组件,使用when Prop提供一个条件以弹出模态。

import { Prompt } from 'react-router-dom'
class MyComponent extends React.Component {
  render() {
    return (
      <div>
        <Prompt
          when={myDataHasNotSavedYet}
          message="This will lose your changes. Are you sure want leave the page?"
        />        
        <RestOfMyComponent/>
      </div>
    )
  }
}

最新更新