代码之家  ›  专栏  ›  技术社区  ›  tic

防止所有子级重新呈现每次setState调用

  •  2
  • tic  · 技术社区  · 6 年前

    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个时,为什么单击时会出现如此多的减速?当使用稍微复杂的自定义组件时,仅使用200个项目时,会注意到显著的减速。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Shawn Andrews    6 年前

    要解决此问题,您需要为行项目创建一个附加组件。这样,它将有一个单独的渲染函数,而不是重新渲染本身,因为行组件没有更改,只有表组件没有更改。

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