防止所有子项重新渲染setState的每个调用

时间:2018-11-19 22:35:38

标签: reactjs

例如,当在表中呈现一长串元素时,对setState的任何调用,无论它是否更改表用于枚举的数据,都会导致每个子对象的重新呈现。

每次选中/取消选中都会重新渲染每个元素。这会导致2000个元素更加复杂,从而大大降低速度。我将使用虚拟化,但是在执行此操作之前,请确保它具有最佳性能。

class App extends React.Component {
  constructor(props) {
    super(props);
    this.onChange = this.onChange.bind(this);
    const rows = Array.from({ length: 200 }, (v, k) => k + 1).map(i => ({
      id: i,
      field1: "hello",
      field2: "cruel",
      field3: "world"
    }));

    this.state = {
      selectedIds: [],
      rows
    };
  }

  onChange(e) {
    const name = e.target.name;
    const checked = e.target.checked;
    const selectedIds = [...this.state.selectedIds];
    if (!checked) {
      const index = selectedIds.findIndex(x => x === name);
      selectedIds.splice(index, 1);
    } else {
      selectedIds.push(name);
    }
    this.setState(state => ({ selectedIds }));
  }

  render() {
    const { rows, selectedIds } = this.state;
    return (
      <div className="App">
        <h5>{selectedIds.length} Rows Selected</h5>
        <table>
          <thead>
            <tr>
              <td>Select</td>
            </tr>
            <tr>
              <td>Field 1</td>
            </tr>
            <tr>
              <td>Field 2</td>
            </tr>
            <tr>
              <td>Field 3</td>
            </tr>
          </thead>
          <tbody>
            {rows.map(row => {
              console.log(row);
              return (
                <tr key={row.id}>
                  <td>
                    <input
                      type="checkbox"
                      onChange={this.onChange}
                      name={row.id}
                    />
                  </td>
                  <td>
                    <div>{row.field1}</div>
                  </td>
                  <td>
                    <div>{row.field2}</div>
                  </td>
                  <td>
                    <div>{row.field3}</div>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    );
  }
}

我从其他答案中看到,重新运行render函数是预期的行为

ReactJS - Does render get called any time "setState" is called?

但是,如果是这样,当该链接中的元素数增加到4000时,为什么单击时会有这么慢的速度?当使用稍微复杂一些的自定义React组件时,如果仅使用200个项目,则会发现速度显着降低。

1 个答案:

答案 0 :(得分:1)

要解决此问题,您需要为行项目创建一个附加组件。这样,它将具有单独的呈现功能,并且不会重新呈现自身,因为行组件没有改变,只有表格组件没有改变。

{rows.map(row => {
    return (
        <RowItem row={row} onChange={this.onChange}>
    );      
}}

,您的新组件将如下所示:

class RowItem extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
        <tr key={this.props.row.id}>
          <td>
            <input
              type="checkbox"
              onChange={this.props.onChange}
              name={this.props.row.id}
            />
          </td>
          <td>
            <div>{this.props.row.field1}</div>
          </td>
          <td>
            <div>{this.props.row.field2}</div>
          </td>
          <td>
            <div>{this.props.row.field3}</div>
          </td>
        </tr>
    );
  }  
}