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

che*_*ry7 4 javascript react-router react-router-redux

我正在尝试使用自定义对话框询问用户确认,然后导航未保存的数据.

按照我的文档:

  componentDidMount() {
      this.props.router.setRouteLeaveHook(
        this.props.route,
        this.routerWillLeave
      )
  }
Run Code Online (Sandbox Code Playgroud)

而不是

  routerWillLeave(nextLocation) {
    if (!this.props.pristine) {
      return 'You have unsaved information, are you sure you want to leave this page?'

    }
Run Code Online (Sandbox Code Playgroud)

我有

  routerWillLeave(nextLocation) {
    if (!this.props.pristine) {
        this.setState({open: true})
        this.forceUpdatate() //necessary or else render won't be called to open dialog
    }
Run Code Online (Sandbox Code Playgroud)

我使用的对话框组件来自材料的UI刚刚期望一个open布尔值来控制对话框,这还需要handleCancelhandleContinue方法,但我不知道如何与它挂起来routerWillLeave.

handleCancel方法很简单,只需关闭对话框:

  handleCancel() {
    this.setState({open: false})
  };
Run Code Online (Sandbox Code Playgroud)

我已将对话框组件包装在名为的组件中 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>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

我可以从父组件中调用它,我在render方法中有这个:

<Notification open={open} handleCancel={this.handleCancel} handleContinue={this.handleContinue}/>
Run Code Online (Sandbox Code Playgroud)

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

Pau*_*l S 8

当你打电话时createHistory,其中一个选项就是getUserConfirmation,它会提示message和一个callback.对于DOM历史(browserHistoryhashHistory),getUserConfirmation调用window.confirm,传递它message.该callback函数接收window.confirm[0] 的返回值.

您需要做的是提供自己的getUserConfirmation复制方法window.confirm.当它被调用时,你应该显示你的模态并callback根据点击的按钮触发.

Notification.js

<Notification>组件应采取迅速messagecallback基于用户的动作来调用功能.

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>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

ModalConfirmation.js

确认模式是不是真的你的用户界面,这就是为什么我在比应用程序的其余部分分开渲染过程渲染它的一部分.

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)
  }
}
Run Code Online (Sandbox Code Playgroud)

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

createConfirmationHistory.js

import createBrowserHistory from 'history/lib/createBrowserHistory'
import createRouterHistory from './createRouterHistory'

export default function(getUserConfirmation) {
  return createRouterHistory(createBrowserHistory({
    getUserConfirmation
  })
}
Run Code Online (Sandbox Code Playgroud)

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')
Run Code Online (Sandbox Code Playgroud)

如果你想使用历史单例,你必须重构一下,否则它应该工作.(虽然我没有对它进行过测试).

[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