state, props,render()
為什么說React是由數據驅動的?
- 當組件的state或者props發生改變時,render函數就會被執行,而頁面又是由render函數渲染出來的,因此說,數據一旦改變頁面就會隨之改變
- 當父組件的render函數被執行時,它的子組件的render函數也會被執行一次
虛擬DOM
React中的render()函數執行效率是非常高的,原因在于React中使用了虛擬DOM
- 原因:減少了JS中創建真實DOM的性能損耗,取而代之的是創建虛擬DOM,就是JS對象,另外在進行對比時減去了真實DOM的對比,取而代之的是虛擬DOM即JS對象的對比,從而提高了性能
1 生成state數據
2 JSX模版
3 生成虛擬DOM(虛擬DOM就是一個JS數組對象,用它來描述真實DOM) --此處會帶來一些新能損耗,但是JS生成一個對象性能損耗是很小的,如果用JS生成一個DOM,會使用webApplication的API,這種性能損耗是很大的
['div', {id: 'abc'}, ['span',{ }, 'hello world']]
4 用虛擬DOM生成真實的DOM,來顯示
<div id='abc'><span>hello world</span></div>
5 state 發生變化
6 數據 + 模版 生成新的虛擬DOM
['div', {id: 'abc'}, ['span',{ }, 'bye bye']]
7 比較原始虛擬DOM和新的虛擬DOM的區別,找到區別是span中的內容
8 直接操作DOM 改變span中的內容
JSX模版生成真實DOM流程
- JSX代碼就是一個模版,并不是真實的DOM,之后React會將模版與state結合,最終生成一個虛擬DOM即JS對象,之后才會生成真實DOM
- jSX -> JS對象 -> 真實DOM
JSX底層如何被轉為JS對象?最終又是如何變為真實DOM?
- 使用了
React.createElement('div',{屬性},'item')
,將一個對象傳給createElement函數,函數內部首先會生成一個虛擬DOM,最終渲染成真實的DOM- jSX -> createElement函數 -> 虛擬DOM(JS對象) -> 真實DOM
虛擬DOM的優點
- 提升了性能
- 得以實現跨端應用(例如RN,得益于虛擬DOM才能實現原生應用,因為如果沒有虛擬DOM,當使用JSX模版和數據結合后去直接渲染真實DOM,在瀏覽器中是沒有問題的,在手機端是不存在DOM這個概念的,因此手機端是無法使用的;當使用了虛擬DOM后,JS對象是可以被手機端識別的,在PC端最終會生成真實DOM,在手機端不會生成真實的DOM,而是生成一些原生的組件)
虛擬DOM中的Diff(Difference)算法
此算法針對上述步驟中的第7步,即比較原始虛擬DOM和新的虛擬DOM的區別,可以提高比對性能
- React底層在調用了
setState
方法時,才會出發Diff算法(setState
方法是異步執行的)
問題:為什么
setState
方法會被React設計成一個異步方法?
場景:如果在很短時間間隔內,連續調用了3次setState
方法,那么React底層可能會調用3次Diff算法進行比對,這樣會很消耗性能
React實現:會將這3次調用setState
方法合并為只調用一次setState
方法,即只做一次虛擬DOM的比對,然后更新一次DOM
1547014058427.jpg
- Diff算法會按照同層比較的方式進行比對
- 如果第一層進行比對時就不一樣,React就不會繼續往下一層比對了,它會將原始的虛擬DOM下的節點全部刪除,然后用重新生成節點下的虛擬DOM替換原始的虛擬DOM下的所有節點
1547014477063.jpg
- 在虛擬DOM比對時,每個節點都會有一個key值,這樣便于與新的虛擬DOM進行比對
- 也是為什么在做循環操作時,不要省略key值,這樣就無法保證在原始虛擬DOM中的key值與新的虛擬DOM的key值保持一致
- 例如在如下循環中,使用了index作為key值時,此時輸入a,b,c
a 對應key值為0 b對應key值為1 c對應key值為2
當刪除a時,此時 b對應key值為0 ,c對應key值為1
那么此時,b之前的key值是1,當前b的key值是0 ,所以就沒有辦法建立起關系了
這就是用index作為key值的一個問題,會導致key值不穩定
return this.state.list.map((item,index) => {
return (
<div key={index}>
<TodoItem
textContent={item}
index={index}
deleteItem={this.handleItemDelete}
/>
</div>
)
})
總結: 同層比較和key值比較都是diff算法的一部分