首页 > 解决方案 > 在反应中,如何使用 onChange 事件定位特定的表行?

问题描述

我有一个包含多行的表,并且每行的最后一列都有一个下拉列表,其中包含 3 个值IncompleteFailPass。如果下拉菜单选择通过,那么我需要显示复选标记图标,如果下拉菜单选择失败,则会显示错误图标。

上述逻辑似乎工作正常。我正在努力解决的是如何仅针对表的特定行而不对其他行产生任何影响。我只想将图标显示到我要定位的行(在本例中为第 1 行)。

例如,这就是我当前的表的样子。它影响了两行: 在此处输入图像描述

对于其他 Fail 选项也是如此:

在此处输入图像描述

这是我的代码的样子:

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

我得到的错误: 未捕获的类型错误:无法读取 null 的属性“值”

标签: javascriptreactjsevent-handling

解决方案


您不应该使用 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
    };
  });
};

编辑:要修复空错误,有两种选择。首先,我们可以同步保存我们关心的值,这样在异步代码运行时就可以使用

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

推荐阅读