默認(rèn)渲染行為的問題
在React Component的生命周期中固棚,有一個(gè)shouldComponentUpdate方法仙蚜。這個(gè)方法默認(rèn)返回值是true。
這意味著就算沒有改變組件的props或者state呜师,也會(huì)導(dǎo)致組件的重繪艳丛。這就經(jīng)常導(dǎo)致組件因?yàn)椴幌嚓P(guān)數(shù)據(jù)的改變導(dǎo)致重繪,這極大的降低了React的渲染效率氮双。比如下面的例子中霎匈,任何options的變化,甚至是其他數(shù)據(jù)的變化都可能導(dǎo)致所有cell的重繪铛嘱。
//Table Component
{this.props.items.map(i =>
<Cell data={i} option={this.props.options[i]} />
)}
重寫shouldComponentUpdate
為了避免這個(gè)問題袭厂,我們可以在Cell中重寫shouldComponentUpdate方法球匕,只在option發(fā)生改變時(shí)進(jìn)行重繪。
class Cell extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
if (this.props.option === nextProps.option) {
return false;
} else {
return true;
}
}
}
這樣每個(gè)Cell只有在關(guān)聯(lián)option發(fā)生變化時(shí)進(jìn)行重繪橄杨。
使用PureComponent與immutable.js
因?yàn)樯厦娴那闆r十分通用照卦,React創(chuàng)建了PureComponent組件創(chuàng)建了默認(rèn)的shouldComponentUpdate行為。這個(gè)默認(rèn)的shouldComponentUpdate行為會(huì)一一比較props和state中所有的屬性采转,只有當(dāng)其中任意一項(xiàng)發(fā)生改變是瞬痘,才會(huì)進(jìn)行重繪。
需要注意的是框全,PureComponent使用淺比較判斷組件是否需要重繪
因此,下面對(duì)數(shù)據(jù)的修改并不會(huì)導(dǎo)致重繪(假設(shè)Table也是PureComponent)
options.push(new Option())
options.splice(0, 1)
options[i].name = "Hello"
這些例子都是在原對(duì)象上進(jìn)行修改克婶,由于淺比較是比較指針的異同丹泉,所以會(huì)認(rèn)為不需要進(jìn)行重繪。
為了避免出現(xiàn)這些問題筋岛,推薦使用immutable.js晒哄。immutable.js會(huì)在每次對(duì)原對(duì)象進(jìn)行添加,刪除寝凌,修改使返回新的對(duì)象實(shí)例。任何對(duì)數(shù)據(jù)的修改都會(huì)導(dǎo)致數(shù)據(jù)指針的變化红符。
其他的陷阱
需要注意的是,還有一些小陷阱需要避免预侯。
- Literal Array與Literal Object
{this.props.items.map(i =>
<Cell data={i} options={this.props.options || []} />
)}
若options為空,則會(huì)使用[]双戳。[]每次會(huì)生成新的Array糜芳,因此導(dǎo)致Cell每次的props都不一樣,導(dǎo)致需要重繪膏斤。解決方法如下:
const default = [];
{this.props.items.map(i =>
<Cell data={i} options={this.props.options || default} />
)}
- 內(nèi)聯(lián)函數(shù)
函數(shù)也經(jīng)常作為props傳遞邪驮,由于每次需要為內(nèi)聯(lián)函數(shù)創(chuàng)建一個(gè)新的實(shí)例,所以每次function都會(huì)指向不同的內(nèi)存地址毅访。比如:
render() {
<MyInput onChange={e => this.props.update(e.target.value)} />;
}
以及:
update(e) {
this.props.update(e.target.value);
}
render() {
return <MyInput onChange={this.update.bind(this)} />;
}
注意第二個(gè)例子也會(huì)導(dǎo)致創(chuàng)建新的函數(shù)實(shí)例喻粹。為了解決這個(gè)問題,需要提前綁定this指針:
constructor(props) {
super(props);
this.update = this.update.bind(this);
}
update(e) {
this.props.update(e.target.value);
}
render() {
return <MyInput onChange={this.update} />;
}
參考資料