React.js:无状态 child 组件数组中的 shouldComponentUpdate
React.js: shouldComponentUpdate in array of stateless child Components
我有一个 parent React class (<EventList />
),其中包含一个 object 存储它的 Child 组件 (<Event />
)数据。为了简洁起见,我省略了很多功能。
EventList
州的背景
/**
* The events state looks like this before the EventList component is rendered:
*
* var events = {
* 1: {
* id: 1,
* title: "Some title"
* },
* 2: {
* id: 2,
* title: "Some other title"
* },
*
* ...
* };
*/
Event.jsx
var Event = React.createClass({
/**
* Pass up the ID of the Event and the new value of the Event's Title
*/
_handleChange: function (e) {
this.props.handleChange(this.props.id, e.target.value);
},
render: function () {
return (
<div className="event">
<input type="text" value={this.props.title} onChange={this._handleChange} />
</div>
);
}
});
EventList.jsx
var EventList = React.createClass({
propTypes: {
events: React.PropTypes.object
},
/**
* Update the State of an event who's title has changed
*/
_handleChange: function (id, title) {
var newState = React.addons.update(this.state.events[id].title, {
$set: title
});
this.setState(newState);
},
render: function () {
var renderedEvents = Object.keys(this.state.events).map(function (id) {
var event = this.state.events[id];
return <Event key={event.id} title={event.title} handleChange={this._handleChange}/>;
}, this);
return (
<div className="events">
{renderedEvents}
</div>
);
}
});
现在这很好,而且可以正常工作。标题的状态得到更新,所有内容都呈现并且 re-renders 成功;但这也是问题所在:
一切re-renders!
列表中的一些事件还不错,但是一旦有很多事件,re-render 就会产生巨大的性能损失,因为 EventList
渲染函数会执行并填充一个新的<Event />
组件数组。
我希望能够做的一件事(尽管假设它需要对应用程序进行完全重组)是能够在 <Event />
组件中使用 shouldComponentUpdate
。
但是,以我目前的关系,我不能这样做。如果您查看 shouldComponentUpdate
的默认参数:
shouldComponentUpdate: function(nextProps, nextState) {...},
您会注意到在 <Event />
级别,this.props
将始终等于 nextProps
,因此请尝试执行以下操作:
shouldComponentUpdate: function(nextProps, nextState) {
return this.props !== nextProps;
},
将始终 return false
因为此时在事物流中它们指向完全相同的数据集。 nextState
当然不存在<Event />
级别。
所以我的问题是,我需要做什么才能摆脱 <EventList />
级别的非常昂贵的 re-render?
问题出在您的更新调用中。目前,您实际上是 var newState = title
。您需要实际更新顶级状态密钥。
_handleChange: function (id, title) {
var update = {};
update[id] = {title: {$set: title}};
var newEvents = React.addons.update(this.state.events, update);
this.setState({events: newEvents});
},
或者使用 ES6 可以避免局部变量:
_handleChange: function (id, title) {
var newEvents = React.addons.update(this.state.events, {
[id]: {
title: {$set: title}
}
});
this.setState({events: newEvents});
},
我有一个 parent React class (<EventList />
),其中包含一个 object 存储它的 Child 组件 (<Event />
)数据。为了简洁起见,我省略了很多功能。
EventList
州的背景
/**
* The events state looks like this before the EventList component is rendered:
*
* var events = {
* 1: {
* id: 1,
* title: "Some title"
* },
* 2: {
* id: 2,
* title: "Some other title"
* },
*
* ...
* };
*/
Event.jsx
var Event = React.createClass({
/**
* Pass up the ID of the Event and the new value of the Event's Title
*/
_handleChange: function (e) {
this.props.handleChange(this.props.id, e.target.value);
},
render: function () {
return (
<div className="event">
<input type="text" value={this.props.title} onChange={this._handleChange} />
</div>
);
}
});
EventList.jsx
var EventList = React.createClass({
propTypes: {
events: React.PropTypes.object
},
/**
* Update the State of an event who's title has changed
*/
_handleChange: function (id, title) {
var newState = React.addons.update(this.state.events[id].title, {
$set: title
});
this.setState(newState);
},
render: function () {
var renderedEvents = Object.keys(this.state.events).map(function (id) {
var event = this.state.events[id];
return <Event key={event.id} title={event.title} handleChange={this._handleChange}/>;
}, this);
return (
<div className="events">
{renderedEvents}
</div>
);
}
});
现在这很好,而且可以正常工作。标题的状态得到更新,所有内容都呈现并且 re-renders 成功;但这也是问题所在:
一切re-renders!
列表中的一些事件还不错,但是一旦有很多事件,re-render 就会产生巨大的性能损失,因为 EventList
渲染函数会执行并填充一个新的<Event />
组件数组。
我希望能够做的一件事(尽管假设它需要对应用程序进行完全重组)是能够在 <Event />
组件中使用 shouldComponentUpdate
。
但是,以我目前的关系,我不能这样做。如果您查看 shouldComponentUpdate
的默认参数:
shouldComponentUpdate: function(nextProps, nextState) {...},
您会注意到在 <Event />
级别,this.props
将始终等于 nextProps
,因此请尝试执行以下操作:
shouldComponentUpdate: function(nextProps, nextState) {
return this.props !== nextProps;
},
将始终 return false
因为此时在事物流中它们指向完全相同的数据集。 nextState
当然不存在<Event />
级别。
所以我的问题是,我需要做什么才能摆脱 <EventList />
级别的非常昂贵的 re-render?
问题出在您的更新调用中。目前,您实际上是 var newState = title
。您需要实际更新顶级状态密钥。
_handleChange: function (id, title) {
var update = {};
update[id] = {title: {$set: title}};
var newEvents = React.addons.update(this.state.events, update);
this.setState({events: newEvents});
},
或者使用 ES6 可以避免局部变量:
_handleChange: function (id, title) {
var newEvents = React.addons.update(this.state.events, {
[id]: {
title: {$set: title}
}
});
this.setState({events: newEvents});
},