反应路由器中的自定义离开对话框 [英] Custom leave dialog in react-router

查看:46
本文介绍了反应路由器中的自定义离开对话框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用户可以编辑内容的表单.如果用户有一些未保存的更改并想离开页面,我想给他一个自定义对话框,询问他是否确定.如果然后导航应该继续并且表单更改标志应该被重置,否则用户应该停留在页面上.

I have a form where the user can edit stuff. If the user has some unsaved changed and wants to leave the page I want to give him a custom dialog, asking him if he is sure. If then the navigation should continue and the form changed flag should be reset, otherwise the user should stay at the page.

在这里您可以检查我当前正在检查此条件的高阶组件.它正在工作,但函数 leave 返回一个字符串,然后 react-router 将在本机警报中显示该文本.

Here you can check my current higher order component which is checking this condition. It is working, but the function leave returns a string and react-router will then display that text in a native alert.

有没有办法在这里显示我的自定义对话框?我还可以获得回调或类似的警报,以便我可以调度一个事件,告诉存储,最新的更改并不重要.

Is there a way that I can show my custom dialog in here? And can I also get a callback or similar of the alert, so that I can dispatch an event which tells the storage, that the latest changes are not important.

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

推荐答案

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

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.

这篇关于反应路由器中的自定义离开对话框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆