React之PureComponent的使用作用
React避免重復渲染
React在渲染出的UI內部建立和維護了一個內層的實現(xiàn)方式,它包括了從組件返回的React元素。這種實現(xiàn)方式使得React避免了一些不必要的創(chuàng)建和關聯(lián)DOM節(jié)點,因為這樣做可能比直接操作JavaScript對象更慢一些,它被稱之為“虛擬DOM”。
當一個組件的props或者state改變時,React通過比較新返回的元素和之前渲染的元素來決定是否有必要更新實際的DOM。當他們不相等時,React會更新DOM。
在一些情況下,你的組件可以通過重寫這個生命周期函數(shù)shouldComponentUpdate來提升速度, 它是在重新渲染過程開始前觸發(fā)的。 這個函數(shù)默認返回true,可使React執(zhí)行更新:
shouldComponentUpdate(nextProps, nextState) {
return true;
}
舉例
如果想讓組件只在props.color或者state.count的值變化時重新渲染,你可以像下面這樣設定shouldComponentUpdate:
class CounterButton extends React.Component {
constructor(props) {
super(props);
this.state = {count: 1};
}
shouldComponentUpdate(nextProps, nextState) {
if (this.props.color !== nextProps.color) {
return true;
}
if (this.state.count !== nextState.count) {
return true;
}
return false;
}
render() {
return (
<button
color={this.props.color}
onClick={() => this.setState(state => ({count: state.count + 1}))}>
Count: {this.state.count}
</button>
);
}
}
在以上代碼中,shouldComponentUpdate只檢查props.color和state.count的變化。如果這些值沒有變化,組件就不會更新。當你的組件變得更加復雜時,你可以使用類似的模式來做一個“淺比較”,用來比較屬性和值以判定是否需要更新組件。這種模式十分常見,因此React提供了一個輔助對象來實現(xiàn)這個邏輯 - 繼承自React.PureComponent。以下代碼可以更簡單的實現(xiàn)相同的操作:
class CounterButton extends React.PureComponent {
constructor(props) {
super(props);
this.state = {count: 1};
}
render() {
return (
<button
color={this.props.color}
onClick={() => this.setState(state => ({count: state.count + 1}))}>
Count: {this.state.count}
</button>
);
}
}
PureComponent
原理
當組件更新時,如果組件的 props 和 state 都沒發(fā)生改變, render 方法就不會觸發(fā),省去 Virtual DOM 的生成和比對過程,達到提升性能的目的。具體就是 React 自動幫我們做了一層淺比較:
if (this._compositeType === CompositeTypes.PureClass) {
shouldUpdate = !shallowEqual(prevProps, nextProps) || !shallowEqual(inst.state, nextState);
}
而 shallowEqual 又做了什么呢?會比較 Object.keys(state | props) 的長度是否一致,每一個 key 是否兩者都有,并且是否是一個引用,也就是只比較了第一層的值,確實很淺,所以深層的嵌套數(shù)據是對比不出來的。
問題
大部分情況下,你可以使用React.PureComponent而不必寫你自己的shouldComponentUpdate,它只做一個淺比較。但是由于淺比較會忽略屬性或狀態(tài)突變的情況,此時你不能使用它。
class ListOfWords extends React.PureComponent {
render() {
return <div>{this.props.words.join(',')}</div>;
}
}
class WordAdder extends React.Component {
constructor(props) {
super(props);
this.state = {
words: ['marklar']
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// This section is bad style and causes a bug
const words = this.state.words;
words.push('marklar');
this.setState({words: words});
}
render() {
return (
<div>
<button onClick={this.handleClick} />
<ListOfWords words={this.state.words} />
</div>
);
}
}
在ListOfWords中,this.props.words是WordAdder中傳入的其state的一個引用。雖然在WordAdder的handelClick方法中被改變了,但是對于ListOfWords來說,其引用是不變的,從而導致并沒有被更新。
解決方法
在上面的問題中可以發(fā)現(xiàn),當一個數(shù)據是不變數(shù)據時,可以使用一個引用。但是對于一個易變數(shù)據來說,不能使用引用的方式給到PureComponent。簡單來說,就是我們在PureComponent外層來修改其使用的數(shù)據時,應該給其賦值一個新的對象或者引用,從而才能確保其能夠進行重新渲染。例如上面例子中的handleClick可以通過以下幾種來進行修改從而確認正確的渲染:
handleClick() {
this.setState(prevState => ({
words: prevState.words.concat(['marklar'])
}));
}
或者
handleClick() {
this.setState(prevState => ({
words: [...prevState.words, 'marklar'],
}));
};
或者針對對象結構:
function updateColorMap(oldObj) {
return Object.assign({}, oldObj, {key: new value});
}
immutable.js
Immutable.js是解決這個問題的另一種方法。它通過結構共享提供不可突變的,持久的集合:
- 不可突變:一旦創(chuàng)建,集合就不能在另一個時間點改變。
- 持久性:可以使用原始集合和一個突變來創(chuàng)建新的集合。原始集合在新集合創(chuàng)建后仍然可用。
- 結構共享:新集合盡可能多的使用原始集合的結構來創(chuàng)建,以便將復制操作降至最少從而提升性能。
// 常見的js處理
const x = { foo: 'bar' };
const y = x;
y.foo = 'baz';
x === y; // true
// 使用 immutable.js
const SomeRecord = Immutable.Record({ foo: null });
const x = new SomeRecord({ foo: 'bar' });
const y = x.set('foo', 'baz');
x === y; // false
總結
PureComponent 真正起作用的,只是在一些純展示組件上,復雜組件使用的話shallowEqual 那一關基本就過不了。另外在使用的過程中為了確保能夠正確的渲染,記得 props 和 state 不能使用同一個引用哦。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
React中useCallback useMemo到底該怎么用
在React函數(shù)組件中,當組件中的props發(fā)生變化時,默認情況下整個組件都會重新渲染。換句話說,如果組件中的任何值更新,整個組件將重新渲染,包括沒有更改values/props的函數(shù)/組件。在react中,我們可以通過memo,useMemo以及useCallback來防止子組件的rerender2023-02-02
ReactNative 之FlatList使用及踩坑封裝總結
本篇文章主要介紹了ReactNative 之FlatList使用及踩坑封裝總結,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11
使用webpack5從0到1搭建一個react項目的實現(xiàn)步驟
這篇文章主要介紹了使用webpack5從0到1搭建一個react項目的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-12-12
JavaScript的React框架中的JSX語法學習入門教程
這篇文章主要介紹了JavaScript的React框架中的JSX語法學習入門教程,React是由Facebook開發(fā)并開源的高人氣js框架,需要的朋友可以參考下2016-03-03

