React 的核心流程能夠分爲兩個部分:javascript
reconciliation (調度算法,也可稱爲 render): // 調和前端
更新 state 與 props;java
調用生命週期鉤子;react
生成 virtual dom;算法
這裏應該稱爲 Fiber Tree 更爲符合;redux
經過新舊 vdom 進行 diff 算法,獲取 vdom change;數組
肯定是否須要從新渲染瀏覽器
commit:性能優化
如須要,則操做 dom 節點更新;babel
constructor ====》 初始化state componentWillMount ==== 》 // 當新 props 中的 data 發生變化時,同步更新到 state 上
componentDidMount ====》進行事件監聽,數據的請求
componentWillUpdate === 》 getSnapshotBeforeUpdate componentDidUpdate ==== 》 當 id 發生變化時,從新獲取數據 shouldComponentUpdate ====》 優化渲染的性能,return false 阻止後面的邏輯 componentWillReciveProps ==== 》少使用,使用 componentWillUnmount ====》 解綁事件getDerivedStateFromPropsgetDerivedStateFromProps
在新版本中,React 官方對生命週期有了新的 變更建議:
- 使用
getDerivedStateFromProps
替換componentWillMount
; - 使用
getSnapshotBeforeUpdate
替換componentWillUpdate
; - 避免使用
componentWillReceiveProps
;
其實該變更的緣由,正是因爲上述提到的 Fiber。首先,從上面咱們知道 React 能夠分紅 reconciliation 與 commit 兩個階段,對應的生命週期以下:
-
reconciliation:
componentWillMount
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
-
commit:
componentDidMount
componentDidUpdate
componentWillUnmount
在 Fiber 中,reconciliation 階段進行了任務分割,涉及到 暫停 和 重啓,所以可能會致使 reconciliation 中的生命週期函數在一次更新渲染循環中被 屢次調用 的狀況,產生一些意外錯誤。
新版的建議生命週期以下:
class Component extends React.Component { // 替換 `componentWillReceiveProps` , // 初始化和 update 時被調用 // 靜態函數,沒法使用 this static getDerivedStateFromProps(nextProps, prevState) {} // 判斷是否須要更新組件 // 能夠用於組件性能優化 shouldComponentUpdate(nextProps, nextState) {} // 組件被掛載後觸發 componentDidMount() {} // 替換 componentWillUpdate // 能夠在更新以前獲取最新 dom 數據 getSnapshotBeforeUpdate() {} // 組件更新後調用 componentDidUpdate() {} // 組件即將銷燬 componentWillUnmount() {} // 組件已銷燬 componentDidUnMount() {} }
使用建議:
- 在
constructor
初始化 state; - 在
componentDidMount
中進行事件監聽,並在componentWillUnmount
中解綁事件; - 在
componentDidMount
中進行數據的請求,而不是在componentWillMount
; - 須要根據 props 更新 state 時,使用
getDerivedStateFromProps(nextProps, prevState)
;- 舊 props 須要本身存儲,以便比較;
-
public static getDerivedStateFromProps(nextProps, prevState) { // 當新 props 中的 data 發生變化時,同步更新到 state 上 if (nextProps.data !== prevState.data) { return { data: nextProps.data } } else { return null1 } }
- 能夠在
componentDidUpdate
監聽 props 或者 state 的變化,例如:
componentDidUpdate(prevProps) { // 當 id 發生變化時,從新獲取數據 if (this.props.id !== prevProps.id) { this.fetchData(this.props.id); } }
- 在
componentDidUpdate
使用setState
時,必須加條件,不然將進入死循環; getSnapshotBeforeUpdate(prevProps, prevState)
能夠在更新以前獲取最新的渲染數據,它的調用是在 render 以後, update 以前;shouldComponentUpdate
: 默認每次調用setState
,必定會最終走到 diff 階段,但能夠經過shouldComponentUpdate
的生命鉤子返回false
來直接阻止後面的邏輯執行,一般是用於作條件渲染,優化渲染的性能。
二: 虛擬DOM的理解
(1)Virtual DOM是對DOM的抽象,本質上是JavaScript對象,這個對象就是更加輕量級的對DOM的描述.
(2)兩個內容的差別,進行dom的對比,事件屬性方法,耗性能,dom對象轉換爲js對象,比較會快。有效提高性能。
(3)首先,咱們都知道在前端性能優化的一個祕訣就是儘量少地操做DOM,不只僅是DOM相對較慢,更由於頻繁變更DOM會形成瀏覽器的迴流或者重回,這些都是性能的殺手,所以咱們須要這一層抽象,在patch過程當中儘量地一次性將差別更新到DOM中,這樣保證了DOM不會出現性能不好的狀況.
(4)更好的跨平臺,好比Node.js就沒有DOM,若是想實現SSR(服務端渲染),那麼一個方式就是藉助Virtual DOM,由於Virtual DOM自己是JavaScript對象.
三:diff算法
(1)diff的目的就是比較新舊Virtual DOM Tree找出差別並更新.
(2)一層節點發現有問題,再也不往下比,直接放棄,n的平方下降爲n
- 把樹形結構按照層級分解,只比較同級元素(層級比較)
- 給列表結構的每一個單元添加惟一的 key 屬性,方便比較(列表添加key)
- React 只會匹配相同 class 的 component(這裏面的 class 指的是組件的名字)
- 選擇性子樹渲染。開發人員能夠重寫shouldComponentUpdate 提升 diff 的性能
四:key值的做用
(1)若是key值相同,dom直接複用,不用再建立dom,直接這兩個比,不用循環比
(2)用新指針對應節點的key去舊數組尋找對應的節點,這裏分三種狀況,
當沒有對應的key,那麼建立新的節點,
若是有key而且是相同的節點,把新節點patch到舊節點,
若是有key可是不是相同的節點,則建立新節點
五:怎麼理解HOC高階組件
接收一些函數,返回函數,組件進行包裝,返回一個新的組件,不少地方都要用,有一點區別,共用的東西寫在高階組件中,經過傳遞額外參數,動態改變組件不一樣場景下使用的差別。
六:redux中間件的原理
action--store-reducer-props action和store之間,溝通的橋樑dispatch,改裝dispatch,
store.dispatch,直接把action(對象)傳遞給store,使用中間件,action能夠是函數,能夠將函數轉換爲對象,傳遞給store。
七:setState發生了什麼?遇到過什麼坑
調和的過程。setState通常怎麼用,傳遞什麼進去,對象仍是方法。
this.setState({ name: '小李' }); this.setState(() =>({ name:'小李' })); 永遠用函數調用,會避免一些坑。 this.setState({ age: this.state.age+1 }); setState異步,瘋狂點擊按鈕,age不是每次加1,會一次加5,6個,state異步,會進行累加 <input refs="input" value={this.state.age} /> ====1 this.setState((prevState) =>{ age: ++ prevState }); this.refs.input.value ==== 1 this.setState((prevState) =>{ age: ++ prevState }, () => { this.refs.input.value // 異步執行完state以後執行 });
八:ref是一個函數,有什麼好處?
方便react在銷燬組件從新渲染,有效清空ref引用中的東西,防止內存泄漏
九:refs做用是什麼,在什麼場景下用過?
操做dom(滾動條,點擊按鈕,滾動條滾動到上面)
圖片展現獲取圖片的寬和高,
十:react中this的指向問題
十一:react-router的實現原理
hash/location
十二:jsx代碼的轉化(babel)
createElement
十三:受控組件和非受控組件
受控:有生命週期
非受控:純函數
十四:函數組件怎麼作性能優化
十五:react-saga的設計思想
改裝dispatch action-----store之間,action能夠是一個函數,能夠執行異步操做
十六:組件是什麼?類是什麼?類被編譯成什麼?
十七:reselect是作什麼使用的?
十八:何時使用異步組件?
十九:xss攻擊,react如何防範?
二十:react怎麼提升性能優化?
shouldComponentUpdate
pureComponent
二十一:ssr
二十二:
- 爲何返回多個標籤或組件必需要用一個標籤或組件包裹?
- 爲何在根本沒有使用
React
這個變量的狀況下還要import React
?
整個UI其實是經過層層嵌套的React.createElement
方法返回的,因此咱們要在文件開頭import React
,不然編譯後就會發現createElement
沒有定義。
React.createElement
執行的結果是一個對象,對象的屬性描述了標籤或組件的性狀,對象再嵌套子對象。若是頂層返回多個標籤,就沒法表達爲一個對象了