单击每个按钮的处理程序错误地返回集

时间:2016-12-14 10:07:41

标签: javascript reactjs

我正在尝试为循环中生成并插入数组的每个按钮添加一个单击处理程序。

但是,单击按钮始终会输出每行按钮的最后一个按钮,而不是特定按钮本身。

我的代码相当冗长,但我们只需要查看time.push()部分和点击处理程序设置。其他一切只是设置

import React from 'react';

import { friendlyTimeSlot, scopedTimeslots } from '../../utilities/helpers';

class TimeSlotStack extends React.Component {

  constructor() {
    super();
    this.clickHandler = this.clickHandler.bind(this);
    this.state = {
      times: undefined
    };
  }

  componentWillMount() {
    this.updatePropsAndState(this.props);
  }

  componentWillReceiveProps(nextProps) {
    this.updatePropsAndState(nextProps);
    this.forceUpdate();
  }

  updatePropsAndState(props) {
    const time = [];
    let matchedTimeSlots;

    if (props.promotionId) {
      matchedTimeSlots = props.timeSlots.filter(timeSlot => {
        const timeSlotsIds = timeSlot.AvailablePromotions.map(p => p.Id);
        if (timeSlotsIds.includes(props.promotionId)) {
          return timeSlot;
        }
        return false;
      });
    } else {
      matchedTimeSlots = props.timeSlots.filter(timeSlot => timeSlot.HasStandardAvailability);
    }

    const scopedTimes = scopedTimeslots(matchedTimeSlots, props.preferredTimeSlot);

    scopedTimes.forEach((item, i) => {
      const friendlyTime = friendlyTimeSlot(item.TimeSlot, true);
      const leaveTimeRequired = item.IsLeaveTimeRequired;

      let itemPromo;
      let leaveTime;
      let itemPrice;

      if (props.promotionId) {
        itemPromo = item.AvailablePromotions.find(ourItem => ourItem.Id === props.promotionId);
        leaveTime = itemPromo.LeaveTime || item.LeaveTime;
        itemPrice = (itemPromo.BasePrice > 0) ? `£${itemPromo.BasePrice}` : '';
      } else {
        leaveTime = item.LeaveTime;
      }

      time.push(
        <button
          className="btn btn-default"
          type="button"
          onClick={(e) => this.clickHandler(e)}
          ref={input => {
            this.button = input;
          }}
          key={i}
          data-time={friendlyTime}
          data-leave-time-required={leaveTimeRequired}
          data-leave-time={leaveTime.slice(0, -3)}
          data-promotion-id={props.promotionId}
        >
          {friendlyTimeSlot(item.TimeSlot)}<br />{itemPrice}
        </button>
      );
    });

    this.setState({
      times: time
    });
  }

  clickHandler(e) {
    e.preventDefault();
    console.log(this.button.dataset);
  }

  render() {
    if (this.state.times && this.props.name && this.props.description) {
      return (
        <div className="panel panel-default">
          <div className="panel-heading">
            <h3 className="panel-title">{this.props.name}</h3>
          </div>
          <div className="panel-body">
            <p>{this.props.description}</p>
            {this.state.times}
          </div>
        </div>
      );
    }

    return (
      <p>No times available.</p>
    );
  }

}

TimeSlotStack.propTypes = {
  name: React.PropTypes.string.isRequired,
  description: React.PropTypes.string.isRequired,
  timeSlots: React.PropTypes.array.isRequired,
  preferredTimeSlot: React.PropTypes.string.isRequired,
  promotionId: React.PropTypes.number
};

export default TimeSlotStack;

当我点击一个按钮时,我总是从每个列表中得到最后一个按钮。希望下面的屏幕截图有助于使这一点更加清晰:

enter image description here

上面的日志来自:

clickHandler(e) {
  e.preventDefault();
  console.log(this.button.dataset);
}

...但是通过单击每行的第一个按钮生成。你可以看到它总是输出最后一个。

我做错了吗?这是我的第一个React项目,让我感到慌乱。如果我做的事情不是可能造成这种情况的 React方式,请告诉我。

谢谢!

1 个答案:

答案 0 :(得分:1)

您正在覆盖button变量,此上下文中的this是对TimeSlotStack实例的引用。要做你想做的事,你需要维护一个按钮列表,例如。

constructor() {
  super();
  this.clickHandler = this.clickHandler.bind(this);
  this.buttons = [];
  this.state = {
    times: undefined
  };
}

....
// using a IFE so `clickHandler` is called with the correct index
((idx) => {
  time.push(
    <button
      className="btn btn-default"
      type="button"
      onClick={(e) => this.clickHandler(e, idx)}
      ref={button => {
        this.buttons.push(button);
      }}
      key={idx}
      data-time={friendlyTime}
      data-leave-time-required={leaveTimeRequired}
      data-leave-time={leaveTime.slice(0, -3)}
      data-promotion-id={props.promotionId}
    >
      {friendlyTimeSlot(item.TimeSlot)}<br />{itemPrice}
    </button>
  );
})(i);
....

clickHandler(e, i) {
  e.preventDefault();
  console.log(this.buttons[i].dataset);
}