日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

淺談React底層實現原理_React

作者:杉菜醬_ ? 更新時間: 2022-09-07 編程語言

1. props,state與render函數關系,數據和頁面如何實現互相聯動?

當組件的state或者props發生改變的時候,自己的render函數就會重新執行。
注意:當父組件的render被執行的時候,子組件的render也會被重新執行一次(因為在父組件的render里面)。
即當綁定的事件改變了state或者props,render函數就會重新執行解析頁面,這時解析的時候就會使用新的數據了,所以頁面就會變化。

2. React中的虛擬DOM

因為只要state、props改變就會重新渲染render,可以想象要不斷的重新渲染頁面對性能要求非常高,實際上render的性能時非常高的,這歸功于虛擬DOM。
首先提前明確DOM的相關操作需要調用web application對性能損耗是比較高的。

常規思路

  • state數據
  • JSX模板
  • 數據+模板相結合,生成真實的DOM來展示。
  • state改變
  • 數據+模板相結合,生成真實的DOM,替換原始的DOM
    缺點:第一次生成了一個完整的DOM片段,第二次又生成了一個完整的DOM片段,第二次的DOM替換第一次的DOM,這樣生成、替換非常的消耗性能。

改良思路(仍使用DOM)

  • state數據
  • JSX模板
  • 數據+模板相結合,生成真實的DOM來展示
  • state改變
  • 數據+模板相結合,生成真實的DOM,并不直接替換原始的DOM
  • 新的DOM(文檔碎片)原始的DOM作對比,找差異(性能損耗大)
  • 找出發生了什么變化,比如找出了只有input框有差異
  • 只用新的DOM中的input元素替換掉老的DOM中的input元素
    缺點:性能提升并不明顯,因為性能消耗在了對比上。

React的思路

  • state數據
  • JSX模板
  • 數據+模板相結合,生成虛擬DOM(虛擬DOM就是一個JS數組對象,完整的描述真實的DOM)( [ ‘ idv ‘ , { id : ‘ abc ‘ } , [ ‘ span ‘ , { } , ‘ hello ‘ ] ] ),用JS生成JS對象性能損耗極小,生成DOM性能損耗大要調用web application。
  • 用虛擬DOM的結構生成真實的DOM,來顯示( < div id=’abc’>< span>hello</ span></ div> )。
  • state發生變化(< div id=’abc’>< span>bye</ span></ div>)
  • 數組+模板生成了新的虛擬DOM( [ ‘ idv ‘ , { id : ‘ abc ‘ } , [ ‘ span ‘ , { } , ‘ bye ‘ ] ] )(極大的提升了性能)
  • 比較原始虛擬DOM和新的虛擬DOM的區別,找到區別是span中的內容(極大的提升了性能)
  • 直接操作DOM改變span中的內容
    總結:減少了對真實DOM的創建和對比,而創建和對比的是JS對象,從而實現了極大的性能飛躍。

深入理解虛擬DOM

Vue與React中的虛擬DOM的原理和步驟是完全一致的。
React中真實DOM的生成步驟:JSX -> createElement方法 -> JS對象(虛擬DOM) -> 真實的DOM。
因此可見,JSX中的div等標簽僅僅是JSX的語法,并不是DOM,僅用于生成JS對象。
其實在React中創建虛擬DOM(JS對象)使用的是(沒有JSX語法也可用下面的方法生成)

// 傳三個參數:標簽 屬性 內容
// <div>item</div>
// 所以其實沒有JSX語法也可以用下面的方式生成
React.createElement('div',{},'item')

虛擬DOM的優點:

  • 性能提升DOM對比變成了JS的對比
  • 它使得跨平臺應用得以實現,React Native(安卓和ios中沒有DOM的概念,使用虛擬DOM(JS對象)在所有應用中都可以被使用,然后變成原生客戶端的組件)

3. 虛擬DOM的diff算法

  • Diff算法用于比較原始虛擬DOM和新的虛擬DOM的區別,即兩個JS對象該如何比對。
  • diff算法全稱為difference算法
  • setState實際上是異步的,這是為了提升react底層的性能,是為了防止時間間隔很短的情況下多次改變state,React會在這種情況下將幾次改變state合并成一次從而提高性能。
  • diff算法是同級比較,假設第一層兩個虛擬DOM節點不一致,就不會往下比了,就會將原始頁面虛擬DOM全部刪除掉,然后用新的虛擬DOM進行全部的替換,雖然有可能有一些性能的浪費,但是由于同層對比的算法性能很高,因此又彌補了性能的損耗。
  • 做list循環的時候有一個key值,這樣比對的時候就可以相對應的比對,找出要改變的,以及不需要渲染的,這樣使用key做關聯,極大地提升了虛擬DOM比對的性能,這要保證在新的虛擬DOM后key值不變,這就說明了為什么做list循環的時候key的值不要是index,因為這樣沒有辦法保證原虛擬DOM和新虛擬DOM的key值一致性,而造成性能的損耗,一般這個key對應后臺數據的唯一id字段,而不是循環的index。

4. React中ref的使用

  • 在react中使用ref來操作DOM
  • 在react中也可以使用e.target來獲取DOM
  • ref這個參數是一個函數
<input
? ? id = "insertArea"
? ? className="input"
? ? value={this.state.inputValue}
? ? onChange={this.handleInputChange}
? ? ref={(input)=>{this.input = input}}
/>

handleInputChange(e){
?? ?// const value = e.target.value; // 原始的方法
?? ?const value = this.input.value;
?? ?this.setState(() => ({
?? ??? ?inputValue: value
?? ?}))
}

一般情況下不推薦使用ref這種方法,因為setState是一個異步函數,因此去操作DOM的時候可能無法正確的輸出頁面的最新DOM情況,有時候比較復雜的操作如動畫之類的,如果一定要使用,就需要在setState的第二個函數,這個是回調函數,在setState完成的時候觸發。

handleBtnClick(e){
    this.setState((prevState)=>({
        list: [...prevState.list, prevState.inputValue], // 展開運算符
        inputValue: '',
    }), ()=>{
        console.log(this.ul.querySelectorAll('div').length);
    });
}

5. React中的生命周期函數

  • 生命周期函數是指在某一個時刻組件會自動調用執行的函數。
  • render函數就是一個生命周期函數的例子,當state或props的時候改變的時刻就會自動執行。
  • contructor 可以理解成一個生命周期函數,在組件被創建的時候就會被執行,但是它是es6語法,不是react特殊的語法。

組件掛載的過程:

  • componentWillMount 在組件即將被掛載到頁面的時刻自動執行,在渲染之前被執行
  • render 進行掛載,是必須存在的
  • componentDidMount 在組件被掛載到頁面之后被執行。
  • 注意:在state和props 改變的時候只有render會執行,componentWillMount和componentDidMount不會執行,他們只會在第一次掛載到頁面的時候被執行。
  • 組件更新:
  • componentWillReceiveProps 兩個條件都要滿足:1. 當一個組件從父組件接收參數 2. 如果這個組件第一次存在于父組件中不會執行,如果這個組件之前已經存在于父組件中,才會執行。
  • shouldComponentUpdate 組件即將被更新之前會執行,如焦點input框的時候,會返回一個true和false來判斷要不要更新。
  • componentWillUpdate 組件更新之前會自動執行,在shouldComponent返回true之后才會執行。
  • componentDidUpdate 組件更新完成之后被執行。
  • 組件去除的過程:
  • componentWillUnmount:但這個組件即將被從頁面中剔除的時候執行。

6. 生命周期函數的使用場景

  • 防止父組件render的時候,子組件也要render,從而提升性能。
  • shouldComponentUpdate(nextProps,nextState){if(nextProps.content !== this.props.content){return true} return false}
  • 頁面初始化的時候,在componentDidMount中發送AJAX請求(推薦),或者在constructor中,千萬不要放在render里面,會造成死循環,也最好不要在componentWillMount中發送ajax,放這里面是沒有問題的,但是如果在react native 中會有問題。
  • react 沒有內置ajax,使用axios。

原文鏈接:https://shancaijiangzi.blog.csdn.net/article/details/125463565

欄目分類
最近更新