在反应中,如何使用onChange事件定位特定的表行?

时间:2018-08-14 13:01:19

标签: javascript reactjs event-handling

我的表包含多行,并且每行的最后一列都有一个下拉列表,其中包含3个值 Incomplete Fail Pass 。如果将下拉列表选择为“通过”,那么我需要显示选中标记图标,如果将下拉列表选择为“失败”,则将显示错误图标。

以上逻辑似乎运行良好。我正在努力的是如何只针对表的特定行而不对其他行产生任何影响。我只想将图标显示在我要定位的行上(在本例中为第1行)。

例如,这就是我当前的表格。它影响到两行: enter image description here

与其他“失败”选项类似:

enter image description here

这是我的代码:

this.state = {
    ...
    test_steps: [],
  status: ""
};

selectStatus(e) {
  var selected = $('.status_list option:selected').text();
  if(selected == "Pass") {
      this.setState({status: e.target.value})
      $('.checkmark').show();
      $('.bug').hide();
      $(".checkmark").css({"display": "inline", "marginLeft": "10px"});
  } else if(selected == "Fail") {
      this.setState({status: e.target.value})
      $('.bug').show();
      $('.checkmark').hide();
      $(".bug").css({"display": "inline", "marginLeft": "10px"});
  } else {
      this.setState({status: e.target.value})
      $('.checkmark').hide();
      $('.bug').hide();
  }
}

tsteps = test_steps.map((testStep, index) => {
  return (
  <tr key={index}>
      <td>{testStep.step_number}</td>
      <td>{testStep.description}</td>
      <td>{testStep.expected_results}</td>
      <td>{testStep.other_info}</td>
      <td>
          <select 
            className="status_list form-control" 
            id="status" 
            onChange={this.selectStatus.bind(this)} // calling selectStatus function
          >
            <option className={styles.emptyVal}></option>
            <option>Incomplete</option>
            <option>Fail</option>
            <option>Pass</option>
          </select>
          <div className="checkmark" style={{display: 'none'}}>
              <i className={`fas fa-check ${styles.check_icon}`}></i>
          </div>
          <div className="bug" style={{display: 'none'}}>
              <i className={`fas fa-bug ${styles.bug_icon}`}></i>
          </div>
          {testStep.status}
      </td>
  </tr>
  );
});

更新的代码:

this.state = {
  test_steps: [],
  status: []
};

selectStatus(event, index) {
  this.setState(oldState => {
    const newStatus = oldState.status.slice();
    newStatus[index] = event.target.value;
    return {
      status: newStatus
    };
  });
};

tsteps = test_steps.map((testStep, index) => {
  return (
  <tr key={index}>
      <td>{testStep.step_number}</td>
      <td>{testStep.description}</td>
      <td>{testStep.expected_results}</td>
      <td>{testStep.other_info}</td>
      <td>
          <select
              className="status_list form-control" 
              value={this.state.status[index]}
              onChange={e => this.selectStatus(e, index)} >
              <option className={styles.emptyVal}></option>
              <option>Incomplete</option>
              <option>Fail</option>
              <option>Pass</option>
            </select>
          {this.state.status[index] === "Pass" && 
              <div className="checkmark">
                <i className={`fas fa-check ${styles.check_icon}`}></i>
              </div>
            }
            {this.state.status[index] === "Fail" && 
              <div className="bug">
                <i className={`fas fa-bug${styles.bug_icon}`}></i>
              </div>
            }        
            {testStep.status}
      </td>
  </tr>
  );
});

我遇到的错误: 未捕获的TypeError:无法读取null的属性“值”

1 个答案:

答案 0 :(得分:0)

您不应该使用jquery手动更改dom。 React不知道您正在这样做,因此您将通过使React无法正确协调dom来制造错误。

相反,您应该使用react的组件状态,然后根据该状态呈现所需的内容。您已经在使用状态来跟踪步骤,您只需要添加状态,然后使用该状态进行渲染即可。因此,请增加您的状态,如下所示:

this.state = {
    ...
    test_steps: [],
    status: [] <--- now an array
};

然后在渲染时,执行以下操作:

test_steps.map((testStep, index) => {
  return (
    <tr key={index}>
      // some components omitted
      <select
        className="status_list form-control" 
        value={this.state.status[index]} <-- now taken from state
        onChange={e => this.selectStatus(e, index)} >
        // options omitted
      </select>
      {this.state.status[index] === "Pass" && 
        <div className="checkmark">
          <i className={`fas fa-check ${styles.check_icon}`}></i>
        </div>
      }
      {this.state.status[index] === "Fail" && 
        <div className="bug">
          <i className={`fas fa-bug${styles.bug_icon}`}></i>
        </div>
      }        
      {testStep.status}
    </tr>
  );
});

在上面的代码中,我使selectStatus期望有一个索引,因此这是selectStatus将如何使用该索引的方法:

selectStatus(event, index) {
  this.setState(oldState => {
    const newStatus = oldState.status.slice();
    newStatus[index] = event.target.value;
    return {
      status: newStatus
    };
  });
};

编辑:要修复null错误,有两个选项。首先,我们可以同步保存我们关心的值,以便异步代码运行时可用

selectStatus(event, index) {
 const val = event.target.value;
 this.setState(oldState => {
    const newStatus = oldState.status.slice();
    newStatus[index] = val;
    return {
      status: newStatus
    };
  });
};

或者我们可以告诉react保存事件对象,而不是重用它。

selectStatus(event, index) {
  event.persist();
  this.setState(oldState => {
    const newStatus = oldState.status.slice();
    newStatus[index] = event.target.value;
    return {
      status: newStatus
    };
  });
};