且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

反应路由器中的自定义离开对话框

更新时间:2022-12-11 16:59:36

由于无法自定义浏览器对话框,因此您必须呈现单独的组件(例如引导模式)并使用回调来确定单击了哪个按钮,以及采取什么行动.

Since customizing browser dialogs is not possible, you'll have to render a separate component (e.g bootstrap modal) and use a callback to determine which button was clicked, and what action to take.

实际上,我最近遇到了您最近面临的同样问题,我能够通过使用 routerWillLeave 并使用来自另一个组件的回调来解决它.

I actually ran into the same problem you're facing very recently, and I was able to solve it by using routerWillLeave and using callbacks from another component.

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 个变量来正确控制所需的行为:

The implementation of customized dialog like this one is unfortunately quite a pain in the back. I had to use 3 variables here to correctly control the desired behavior:

  • waitingForConfirm - 防止逻辑在用户确认导航时第二次运行所必需的.具体来说,当回调运行并且我们执行 this.context.router.push(route.pathname) 时,routerWillLeave 将再次运行(!),但由于我们已经确认导航,我们必须防止这个逻辑再次运行.

  • waitingForConfirm - necessary to prevent the logic from running a second time when the user confirms to navigate out. Specifically, when the callback is run and we do this.context.router.push(route.pathname), the routerWillLeave will run again(!), but since we've already confirmed navigation we must prevent this logic from running again.

_hasUnsavedChanges() - 检查是否有任何输入字段已更改(没有理由询问是否没有要保存的更改).

_hasUnsavedChanges() - checks if any input fields have changed (no reason to ask if there's no changes to be saved).

clickedSave - 如果用户点击了 Save,不要求确认 - 我们知道我们想离开.

clickedSave - don't ask for confirmation if the user clicked Save - we know we want to leave.

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

显然,您必须自定义上述代码段以适合您的应用程序,但希望它能够提供有关如何解决问题的一些见解.

Obviously, you'll have to customize the above snippets to fit your application, but hopefully it will provide some insight into how to solve the problem.