本文是《深入React技術棧》讀書筆記,其中的很多都已經運用到實際項目中
更多筆記可以star我的github,上面基本都是平時的學習筆記,以及項目中的實踐心得,歡迎關注
影響網頁性能一個較大的因素是瀏覽器的重繪reflow
和重排版repaint
。
我們通過拆分組件為子組件,進而對組件進行更細粒度的控制。這也是函數式變成的魅力之一,保持純凈的狀態;可以讓方法和組件更加專注,體積更小,更獨立,更有復用性和測試性
PureRender的本質
官方提供了react-addons-pure-render-mixin
的插件,其原理為重新實現shouldComponentUpdate
的方法,當前的state
和props
與之前做淺比較,如果返回fales
,就不會調用render
方法
但是默認的shouldComponentUpdate
方法是默認的深比較。但是深比較的代價十分昂貴,就如下面的代碼
shouldComponentUpdate(nextProps, nextState) {
return isDeepEqual(this.props, nextProps) && isDeepEqual(this.state, nextState);
}
然而PureRender
只對值進行了淺比較,以下是shollowEqual
的示例代碼
function shallowEqual(obj, newobj) {
if(obj === newobj) {
return true;
}
}
const objkeys = Object.keys(obj);
const newobjkeys = Object.keys(newobj);
if(objkeys.length !== newobjkeys.length) {
return false;
}
// 以下是關鍵代碼
return objkeys.every(key => {
return newobj[key] === newobjkeys[key];
})
運用PureRender
利用createClass
構建組件時,可以使用官方插件react-addons-pure-render-mixin
import PureRenderMixin from 'react-addons-pure-render-mixin';
class App extends Component {
constructor(props) {
super(props);
this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
}
return <div className={this.props.className}>foo</div>
}
優化PureRender
- 直接將props設置為對象或者數組
我們知道,每次調用React組件其實都會重新創建組件。就算傳入的數組或對象的值沒有改變,他們引用的地址也會改變
<Account style={{color: 'red'}} />
這樣設置的props每次渲染都會創建新對象。這樣的操作,我們只需要提前將其賦值為常量,不直接使用字面量即可
const defaultStyle = {};
<Account style={this.props.style || defaultStyle} />
- 設置props方法並通過事件綁定在元素上面
// 事件綁定寫入到構造函數中
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
- 設置子組件
const NameItem = () => <Item><span>Arthur</span></Item>;
// 上面的組件翻譯過來其實是
const NameItem = () =>
<Item
children={React.createElement('span', {}, 'Arthur')}
/>
顯然上面Item組件不管什么情況下都會直接渲染,那么如何避免這種情況
import React, {Component} from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
class NameItem extends Component {
constructor(props) {
super(props);
this.shouldComponentUpdata = PureRenderMixin.shouldComponentUpdate.bind(this);
}
render() {
return (
<Item><spanArthur</span>></Item>
)
}
}
Immutable
Immutable Data
就是一旦被創建,就不能更改的數據,對Immutable Data
對象進行修改添加或者刪除操作,都會返回一個Immutable
對象,實現的原理就是持久化數據結構。
Immutable
使用舊數據創建新數據時,要保證舊的數據可用但是不可變,同時為了避免將所有的節點都復制一遍帶來的性能損耗,Immutable
使用結構共享,即如果對象樹中一個節點發生變化,只修改這個節點和它受影響的父節點
- Map 鍵值對的集合,對應於Object,ES6也有專門的Map對象
- List 有序可重復對象,對應於Array
- ArrayList 無序不可重復列表
Immutable.is
為了直接比較兩個對象的值,可以使用Immutable.is
來作比較
let map1 = Immutable.Map({a: 1, b:2});
let map2 = Immutable.Map({a: 1, b:2});
Immutable.is(map1, map2); // true
Immutable.is比較的是兩個對象的hashCode或valueOf,由於immutable內部使用了trie數據接口來存儲,只要兩個對象的hashCode相等,值就是一樣的,這樣做的效率非常之高
react-addons-create-fragment
當有兩個子組件需要渲染時,我們沒辦法給他設置key。這個時候可以使用官方提供的插件
import React, {Component} from 'react';
import {render} from 'react-dom';
import createFragment from 'react-addons-create-fragment';
const first = <li>first</li>;
const second = <li>second</li>;
const Rank = ({first, second}) => {
const children = createFragment({
first,
second
});
return <ul>{children}</ul>;
};
render(<Rank first={first} second={second} />, document.getElementById('app'))