Javascript 反应:更新列表中的一个项目,而不重新创建所有项目

Javascript 反应:更新列表中的一个项目,而不重新创建所有项目,javascript,reactjs,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

假设我有一个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...
  }
}
// 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);
类父级扩展React.Component{
render(){
//this.state.list是包含1000项的列表
返回;
}
}
类列表扩展了React.Component{
render(){
//在这里,我们循环浏览这个.props.list并创建1000个新项目
var list=this.props.list.map(项=>{
返回;
});
返回{list};
}
}
类项扩展了React.Component{
shouldComponentUpdate(){
//在这里,我比较了新旧状态/道具
}
render(){
//这里有一些渲染。。。
}
}
对于一个相对较长的列表,map()大约需要10-20ms,我可以注意到接口中有一个小的延迟

当我只需要更新一个对象时,是否可以防止每次重新创建1000个React对象

编辑

我最初的建议只是针对可能的效率改进 列出并没有解决有关限制重新渲染的问题 由于列表更改而导致的组件数量

参见@的答案,以获得原始问题的清晰解决方案


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


您可以使用任何状态管理库来执行此操作,这样您的
家长就不会跟踪
此.state.list
=>您的
列表
仅在添加新的
时才会重新呈现。单个
在更新时将重新呈现

假设您使用
redux

您的代码将如下所示:

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...
  }
}
// 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);
//Parent.js
类父类扩展了React.Component{
render(){
返回;
}
}
//List.js
类列表扩展了React.Component{
render(){
var list=this.props.list.map(项=>{
返回;
});
返回{list};
}
}
常量mapStateToProps=(状态)=>({
列表:getList(状态)
});
导出默认连接(MapStateTops)(列表);
//Item.js
类项扩展了React.Component{
shouldComponentUpdate(){
}
render(){
}
}
const mapStateToProps=(state,ownProps)=>({
项目:getItemByKey(ownProps.uniqueKey)
});
导出默认连接(MapStateTops)(项目);
当然,您必须实现reducer和两个选择器
getList
getItemByKey


这样,如果添加了新元素或更改了
item.key
(您不应该这样做)

避免在组件列表中循环每个渲染的一种方法是在渲染函数之外执行,并将其保存到变量中

class Item extends React.Component {
    shouldComponentUpdate(nextProps, nextState) {
        return this.props.item != nextProps.item;
    }

    render() {
        return <li>{this.props.item}</li>;
    }
}

class List extends React.Component {
    constructor(props) {
        super(props);
        this.items = [];
        this.update = this.update.bind(this);
    }

    componentWillMount() {
        this.props.items.forEach((item, index) => { this.items[index] = <Item key={index} item={item} /> });
    }

    update(index) {

        this.items[index] = <Item key={index} item={'item changed'} />
        this.forceUpdate();
    }

    render() {
        return <div>
            <button onClick={() => { this.update(199); }}>Update</button>
            <ul>{this.items}</ul>
        </div>
    }
}
类项扩展React.Component{
shouldComponentUpdate(下一步,下一步状态){
返回this.props.item!=nextrops.item;
}
render(){
返回
  • {this.props.item}
  • ; } } 类列表扩展了React.Component{ 建造师(道具){ 超级(道具); 此参数为.items=[]; this.update=this.update.bind(this); } 组件willmount(){ this.props.items.forEach((item,index)=>{this.items[index]=}); } 更新(索引){ 此.items[索引]= 这个.forceUpdate(); } render(){ 返回 {this.update(199);}>update
      {this.items}
    } }
    您可以做以下几件事:

  • 构建时,请确保将NODE_ENV设置为production。e、 g.
    NODE\u ENV=生产npm运行构建
    或类似。当
    NODE_ENV
    未设置为生产时,ReactJS执行许多安全检查,例如PropType检查。关闭这些选项将使React渲染的性能提高2倍以上,这对于产品构建至关重要(尽管在开发过程中关闭它-这些安全检查有助于防止bug!)。您可能会发现这对于您需要支持的项目数量来说已经足够好了
  • 如果元素位于可滚动的面板中,并且只能看到其中的一些元素,则可以设置只渲染可见的元素子集。当项目具有固定高度时,这是最简单的。基本方法是将
    firstRendered
    /
    lastredered
    道具添加到列表状态(当然是第一个包含,最后一个排除)。在
    List.render
    中,渲染一个正确高度(
    firstRendered*itemHeight
    )的填充空格
    div
    (或
    tr
    ),然后渲染项目范围
    [firstRendered,lastredered)
    ,然后是另一个具有剩余高度的填充div(
    (totalItems-lastredered)*itemHeight
    )。确保为填充项和items指定了固定键。然后只需处理可滚动div上的onScroll,并确定要渲染的正确范围(通常,您希望渲染顶部和底部的适当重叠,也只希望在接近设置状态边缘时触发设置状态以更改范围)。更疯狂的选择是渲染并实现您自己的滚动条(我认为Facebook自己的FixedDataTable就是这样做的-).这里有很多这种通用方法的例子
  • 使用状态管理库使用横向加载方法。对于较大的应用程序,这是至关重要的。与其从顶部向下传递项的状态,不如让每个项从“全局”状态(如经典通量)或通过React上下文(如现代通量实现、MobX等)检索自己的状态。这样,当项目更改时,只有该项目需要重新渲染

  • 当您更改数据时,默认操作是呈现所有子组件,并创建虚拟dom以判断哪个组件需要重新呈现

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

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