【问题标题】:Remember bind on this in react between mutiple functions记住在多个函数之间的反应中绑定 this
【发布时间】:2017-03-02 21:49:53
【问题描述】:

我有一个反应调度应用程序。如果用户尝试在接下来的 45 小时内安排某事,那么我想向他们发送一条警报消息,让他们可以确认他们选择的时间或更改时间。

我有一个组件Timepicker 处理用户选择的时间并返回用户选择的hour and minutes,如下所示:

renderTimes() {

    return this.props.availabilities.map(function(_av, i) {
    let av = new Date(_av);

    return (
        <a key={i} onClick={this.checkBookingWindow.bind(av.getHours(), av.getMinutes())} className="time-option">
      {_pretty_time(av.getHours(), av.getMinutes())}
    </a>
    );
    }.bind(this));
}

checkBookingWindow函数如下:

checkBookingWindow(hour, minute) {
    var time = new Date().getHours();
    let booking_window = Math.abs(time - hour);
    if (booking_window < 45 && this.state.waive_alert == false) {
        this.setState({open_popup: true});
    } else if (booking_window < 45 && this.state.waive_alert == true) {
        console.log("Waived all rights!");
        //(a) PLAN WAS TO ADD THE CALLBACK OVER HERE!
    } else if (booking_window > 45) {
        console.log("Booking window over 5 hours");
    }
 }

如果时间小于 45 并且如果用户没有放弃警报,那么它应该会弹出弹出窗口并呈现如下:

renderWarningPopup() {
if (this.state.open_popup) {
  return(
                <div>
                    <div className="dashboard-modal">
                        <div className="dashboard-modal-header">
                            <span onClick={this.handleCancel.bind(this)} className="icon-cancel modal-close"></span>
                        </div>
                        <div className="dashboard-modal-body">
                            <p className="small-body-text text-center">Your session is going to happen within the next 45 hours.</p>
                            <p className="small-body-text buffer-bottom-25 buffer-bottom-10-mobile text-center">Are you sure?</p>
                            <div className="schedule-alert-buttons">
                                <button onClick={this.handleCancel.bind(this)} className="btn btn-change-booking">Change Time</button>
                                <button onClick={this.handleSubmit.bind(this)} className="btn btn-confirm-booking">Yes</button>
                            </div>
                        </div>
                    </div>
                    <div className="modal-bg bg-transparent-black"></div>
                </div>
  )}
}

在这里点击Yes,用户之前选择的时间和日期应该被提交,我为此做了以下功能:

handleSubmit(evt) {
  evt.preventDefault();
  this.setState({ waive_alert: true});
  this.checkBookingWindow();
}

但由于显而易见的原因,它不会保留所选的小时和分钟值。在 React 中有没有办法做到这一点?

在更改代码以引发警报之前,我的renderTimes() 如下:

renderTimes() {

    return this.props.availabilities.map(function(_av, i) {
    let av = new Date(_av);

    return (
        <a key={i} onClick={this.props.onSelect.bind(null, av.getHours(), av.getMinutes())} className="time-option">
      {_pretty_time(av.getHours(), av.getMinutes())}
    </a>
    );
    }.bind(this));
}

所以我只是做了一个回调,它将返回选定的 hourminutes。我现在想在 (a) 处做同样的事情,但前提是用户选择 Yes

【问题讨论】:

  • 为什么不把选定的小时和分钟放在任何一个状态上,或者只放在你的反应类的属性上。
  • bind 不能这样工作。调用bind 会返回一个新函数,其中包含绑定上下文(this) 和需要在某处持久化的参数。此外,由于您正在设置状态并且状态在this 中可用 - 正如@JohnRuddell 所提到的 - 将小时和分钟置于状态并从状态访问值有什么危害?

标签: javascript jquery reactjs callback


【解决方案1】:

您可以尝试在单击后将小时/分钟保存到类变量中,然后在handleSumbit() 中您可以使用这些变量调用checkBookingWindow()

在 Timepicker 组件中定义: let selectedHour, selectedMinute;

checkBookingWindow():

checkBookingWindow(hour, minute) {
   var time = new Date().getHours();
   let booking_window = Math.abs(time - hour);
   if (booking_window < 45 && this.state.waive_alert == false) {

    /* NEW CODE */
    this.selectedHour = hour;
    this.selectedMinute = minute;

    this.setState({open_popup: true});
   } else if (booking_window < 45 && this.state.waive_alert == true) {
      console.log("Waived all rights!");
      //(a) PLAN WAS TO ADD THE CALLBACK OVER HERE!
   } else if (booking_window > 45) {
      console.log("Booking window over 5 hours");
   }
}

最后,在handleSubmit()

handleSubmit(evt) {
  evt.preventDefault();
  this.setState({ waive_alert: true});
  this.checkBookingWindow(this.selectedHour, this.selectedMinute);
}

为了确保handleSubmit() 知道this 是Timepicker 组件,您需要确保绑定它。看起来您已经这样做了,因为您将其称为onClick={this.handleSubmit.bind(this)},所以您应该一切都好。另一种方法是使用arrow functions,因此您可以将其定义为handleSubmit= () =&gt; {},而不是handleSubmit() {}。然后你可以输入onClick={this.handleSubmit}

【讨论】:

  • @anonn023432 将它添加到状态对于这个用例来说非常好。如果您真的不想,那么您可以将其添加到课程中。 this.hour = hourthis.minute = minute
  • 是的,确认操作的概念与重新渲染有关,但是如果将来需要更新存储的选定小时/分钟而不重新渲染怎么办?通过添加它来声明您可能会增加技术债务。而且它的开销更大,并为adding things to state when they really don't need to be 开创了一个不好的先例。我认为我们都同意,从技术上讲,您可以将这些变量添加到 state 并让它与现有代码一起正常工作,但我正在讨论您应该做什么。
  • 当然我明白你在说什么,我仍然认为将它添加到状态中是可以的。我已经看到了相反的情况,其中 forceUpdate() 由于变量未处于状态而必须被调用很多。 def 必须在两者之间取得平衡。就浏览器性能而言,除非您为此用例执行视频(60 fps)设置状态之类的事情,否则不会有问题。如果您看到我不久前发布的关于我引用状态和本地类变量的问题的评论一个潜在的解决方案。两者都是可能的并且是可行的
  • @JohnRuddell 这对我的情况很有意义。我想我会按照 erikamjoh 的建议将它存储在变量中,以防止将来出现任何问题。但是感谢您的帮助
  • @JohnRuddell,关于 forceUpdate() 的好点,我同意 def 需要保持平衡 - anonn023432 应该记住这一点,如果你确实需要选择小时/分钟来导致重新渲染,您应该将它们移动到状态而不是调用 forceUpdate()。只要您意识到这一点,出于我之前提到的原因,我倾向于将其存储在变量中。 Def 同意这两种解决方案都是可行且可行的。
猜你喜欢
  • 2018-07-13
  • 2015-03-25
  • 2016-12-22
  • 1970-01-01
  • 1970-01-01
  • 2018-06-03
  • 1970-01-01
  • 2021-11-07
相关资源
最近更新 更多