React:更新列表中的一个项目而不重新创建所有项目

ch1*_*1p_ 37 javascript reactjs

假设我有1000个项目的列表.我用React渲染它,​​像这样:

class Parent extends React.Component {
  render() {
    // this.state.list is a list of 1000 items
    return <List list={this.state.list} />;
  }
}

class List extends React.Component {
  render() {
    // here we're looping through this.props.list and creating 1000 new Items
    var list = this.props.list.map(item => {
      return <Item key={item.key} item={item} />;
    });
    return <div>{list}</div>;
  }
}

class Item extends React.Component {
  shouldComponentUpdate() {
    // here I comparing old state/props with new
  }
  render() {
    // some rendering here...
  }
}
Run Code Online (Sandbox Code Playgroud)

使用相对较长的列表映射()需要大约10-20ms,我可以注意到界面中的小延迟.

每当我只需要更新一个时,我可以阻止重新创建1000个React对象吗?

xia*_*406 18

您可以使用任何状态管理库来执行此操作,以便在添加新内容时Parent不会跟踪this.state.list=>您List唯一的重新呈现Item.个人Item将在更新时重新呈现.

让我们说你用redux.

你的代码会变成这样:

// Parent.js
class Parent extends React.Component {
  render() {        
    return <List />;
  }
}

// List.js
class List extends React.Component {
  render() {        
    var list = this.props.list.map(item => {
      return <Item key={item.key} uniqueKey={item.key} />;
    });
    return <div>{list}</div>;
  }
}

const mapStateToProps = (state) => ({
  list: getList(state)
});

export default connect(mapStateToProps)(List);


// Item.js
class Item extends React.Component {
  shouldComponentUpdate() {
  }
  render() {
  }
}

const mapStateToProps = (state, ownProps) => ({
  item: getItemByKey(ownProps.uniqueKey)
});

export default connect(mapStateToProps)(Item);
Run Code Online (Sandbox Code Playgroud)

当然,你必须实现reducer和两个选择器getListgetItemByKey.

有了这个,List如果添加了新元素,或者如果你改变了item.key(你不应该改变),你将重新渲染你的触发器

  • 这是这样做的方法。也许从数据不必通过“父代”和“列表”组件传输开始,就可以开始回答,这样他们就不需要重新渲染(因此,所有子代都不需要重新渲染) 。 (2认同)

Pin*_*eda 9

编辑:

我的初始建议仅解决了渲染列表可能的效率改进问题,并没有解决由于列表更改而限制组件重新渲染的问题.

请参阅@ xiaofan2406的答案,以获得原始问题的清晰解决方案.


有助于使渲染长列表更有效和简单的库:

反应无限

反应虚拟化

  • 这限制了重新定义的React组件的数量,但是_enes not_阻止重新呈现未更改的组件(请参阅xiaofan2406的回答).我相信后者是加速更新的更好解决方案,而您的解决方案应该用于加速初始渲染.这两种解决方案当然可以一起使用. (2认同)

qiu*_*tao 7

当你更改数据时,react 默认操作是渲染所有子组件,并创建虚拟 dom 来判断哪个组件需要重新渲染。

所以,如果我们能让 react 知道只有一个组件需要重新渲染。它可以节省时间。

您可以shouldComponentsUpdate在列表组件中使用。

如果在这个函数中返回false,react不会创建虚拟dom来判断。

我假设你的数据是这样的 [{name: 'name_1'}, {name: 'name_2'}]

class Item extends React.Component {
  // you need judge if props and state have been changed, if not
  // execute return false;
  shouldComponentUpdate(nextProps, nextState) { 
    if (nextProps.name === this.props.name) return false;

    return true;
  }
  render() {
    return (
      <li>{this.props.name}</li>
   )
  }
}
Run Code Online (Sandbox Code Playgroud)

由于反应只是渲染已更改的组件。因此,如果您只更改一项的数据,则其他项将不会进行渲染。