Javascript 反应:更新列表中的一个项目,而不重新创建所有项目
假设我有一个1000项的清单。我用React渲染它,如下所示: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
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