前言
相信很多新手朋友們對於React、Redux、React-Redux這三者之間的關係和區別肯定有很多不解和疑惑。這裡我們就來詳細的剖析一下它們吧。
React
:負責元件的UI介面渲染;
Redux
:資料處理中心;
React-Redux
:連線元件和資料中心,也就是把React和Redux聯絡起來。
React
React主要就是用來實現UI介面的,是一個專注於view層的框架。對於一些小專案,如果資料的互動不是很多,完全可以只使用React就能很好的實現。
在傳統的頁面開發模式中,需要多次的操作DOM來進行頁面的更新,我們都知道對DOM的操作會造成極大的效能問題。而React的提出就是減少對DOM的操作來提升效能,也就是Virtual DOM。
Virtual DOM
Virtual DOM就相當於一個虛擬空間,React就是基於 Virtual DOM 來工作的。
它的工作過程是:當有資料需要進行更新時,會先計算 Virtual DOM ,並和上一次的 Virtual DOM 做對比,得到DOM結構的區別,然後只會將需要變化的部分批量的更新到真實的DOM上。
說到如何去計算Virtual DOM,在React裡面,用到的是react-diff演算法。我們都知道傳統的diff演算法是通過迴圈遞迴對每個節點進行依次對比,效率低下,演算法複雜度達到了 O(n^3),其中 n 是樹中節點的總數。
根據react diff策略:
- Web UI 中 DOM 節點跨層級的移動操作特別少,可以忽略不計;
- 擁有相同類的兩個元件將會生成相似的樹形結構,擁有不同類的兩個元件將會生成不同的樹形結構;
- 對於同一層級的一組子節點,它們可以通過唯一 id 進行區分。
React 分別對 tree diff、component diff 以及 element diff 進行了演算法優化:
tree diff
:對樹進行分層比較,兩棵樹只會對同一層次的節點進行比較component diff
:
- 如果是同一型別的元件,按照原策略繼續比較 virtual DOM tree。
- 如果不是,則將該元件判斷為 dirty component,從而替換整個元件下的所有子節點。
- 對於同一型別的元件,有可能其 Virtual DOM 沒有任何變化,如果能夠確切的知道這點那可以節省大量的 diff 運算時間,因此 React 允許使用者通過 shouldComponentUpdate() 來判斷該元件是否需要進行 diff。
element diff
:當節點處於同一層級時,React diff 提供了三種節點操作,分別為:插入、移動、刪除。
這是整個react diff演算法的比較流程圖:
React生命週期
React總共有10個周期函式(render重複一次),這10個函式可以滿足我們所有對元件操作的需求,利用的好可以提高開發效率和元件效能。
一、元件在初始化時會觸發5個鉤子函式:
getDefaultProps()
設定預設的props,es6中用 static dufaultProps={}
設定元件的預設屬性。在整個生命週期只執行一次。
getInitialState()
在使用es6的class語法時是沒有這個鉤子函式的,可以直接在constructor中定義this.state。此時可以訪問this.props。
componentWillMount()
ajax資料的拉取操作,定時器的啟動。
元件初始化時呼叫,以後元件更新不呼叫,整個生命週期只呼叫一次,此時可以修改state。
render()
React最重要的步驟,建立虛擬dom,進行diff演算法,更新dom樹都在此進行。此時就不能更改state了。
componentDidMount()
動畫的啟動,輸入框自動聚焦
元件渲染之後呼叫,可以通過this.getDOMNode()獲取和操作dom節點,只呼叫一次。
二、在更新時也會觸發5個鉤子函式:
componentWillReceivePorps(nextProps)
元件初始化時不呼叫,元件接受新的props時呼叫。不管父元件傳遞給子元件的props有沒有改變,都會觸發。
shouldComponentUpdate(nextProps, nextState)
React效能優化非常重要的一環。元件接受新的state或者props時呼叫,我們可以設定在此對比前後兩個props和state是否相同,如果相同則返回false阻止更新,因為相同的屬性狀態一定會生成相同的dom樹,這樣就不需要創造新的dom樹和舊的dom樹進行diff演算法對比,節省大量效能,尤其是在dom結構複雜的時候。不過呼叫this.forceUpdate會跳過此步驟。
componentWillUpdate(nextProps, nextState)
元件初始化時不呼叫,只有在元件將要更新時才呼叫,此時可以修改state
render()
不多說
componentDidUpdate()
元件初始化時不呼叫,元件更新完成後呼叫,此時可以獲取dom節點。
三、解除安裝鉤子函式
componentWillUnmount()
定時器的清除
元件將要解除安裝時呼叫,一些事件監聽和定時器需要在此時清除。
Redux
Redux是一種架構模式,是由flux發展而來的。
Redux三大原則
- 唯一資料來源
- 狀態只讀
- 資料改變只能通過純函式(reducer)完成
Redux核心api
Redux主要由三部分組成:store,reducer,action。
store
Redux的核心是store,它由Redux提供的 createStore(reducer, defaultState) 這個方法生成,生成三個方法,getState(),dispatch(),subscrible()。
- getState():儲存的資料,狀態樹;
- dispatch(action):分發action,並返回一個action,這是唯一能改變store中資料的方式;
- subscrible(listener):註冊一個監聽者,store發生變化的時候被呼叫。
reducer
reducer是一個純函式,它根據previousState和action計算出新的state。
reducer(previousState,action)
action
action本質上是一個JavaScript物件,其中必須包含一個type欄位來表示將要執行的動作,其他的欄位都可以根據需求來自定義。
const ADD_TODO = 'ADD_TODO'
複製程式碼
{
type: ADD_TODO,
text: 'Build my first Redux app'
}
複製程式碼
整合
他們三者之間的互動,可以由下圖概括:
React-Redux
Redux 本身和React沒有關係,只是資料處理中心,是React-Redux讓他們聯絡在一起。
React-rRedux提供兩個方法:connect和Provider。
connect
connect連線React元件和Redux store。connect實際上是一個高階函式,返回一個新的已與 Redux store 連線的元件類。
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
複製程式碼
TodoList是 UI 元件,VisibleTodoList就是由 react-redux 通過connect方法自動生成的容器元件。
mapStateToProps
:從Redux狀態樹中提取需要的部分作為props傳遞給當前的元件。mapDispatchToProps
:將需要繫結的響應事件(action)作為props傳遞到元件上。
Provider
Provider實現store的全域性訪問,將store傳給每個元件。
原理:使用React的context,context可以實現跨元件之間的傳遞。
總結
下圖闡述了它們三者之間的工作流程: