1、定義與功能react
React-Redux 將全部組件分紅兩大類:UI 組件(presentational component)和容器組件(container component)算法
一、UI 組件特徵:redux
this.state
這個變量)this.props
)提供二、容器組件特徵:ide
總結:函數
UI 組件負責 UI 的呈現,容器組件負責管理數據和邏輯。性能
React-Redux 規定,全部的 UI 組件都由用戶提供,容器組件則是由 React-Redux 自動生成。也就是說,用戶負責視覺層,狀態管理則是所有交給它。this
2、使用與方法spa
一、connect方法 輸入UI組件, 輸出容器組件code
React-Redux 提供connect
方法,用於從 UI 組件生成容器組件。component
// TodoList-> UI組件; VisibleTodoList -> 容器組件 // mapStatetoProps,mapDispatchToProps -> 它們定義了 UI 組件的業務邏輯。 // mapStatetoProps 可省略,若省略,UI 組件就不會訂閱Store,就是說 Store 的更新不會引發 UI 組件的更新 import { connect } from 'react-redux' const VisibleTodoList = connect(mapStatetoProps, mapDispatchToProps)(TodoList);
(1) mapStateToProps(
state
[,props
]) 負責輸入邏輯,即將state
映射到 UI 組件的參數(props
)
state: 必選,
state
對象;props: 可選,
表明容器組件的
props
對象mapStateToProps
會訂閱 Store,每當state
更新的時候,就會自動執行,從新計算 UI 組件的參數(props),從而觸發 UI 組件的從新渲染。
// map Redux state to component props (把 Redux state 映射到 component props) const mapStatetoProps = (state) => { return {num: state} } // 使用ownProps做爲參數後,若容器組件的參數(ownProps)發生變化,也會引起 UI 組件從新渲染 const mapStateToProps = (state, ownProps) => { return { active: ownProps.filter === state.visibilityFilter } }
(2) mapDispatchToProps 負責輸出邏輯,即將用戶對 UI 組件的操做映射成 Action。
// map Redux actions to component props (把 Redux actions 映射到 component props) const mapDispatchToProps = dispatch => { return { onIncreaseClick: () => dispatch(increaseAction) }; }
mapDispatchToProps 分爲兩種類型:函數和對象
mapDispatchToProps
是一個函數,會獲得dispatch
和ownProps
(容器組件的props
對象)兩個參數。
mapDispatchToProps
做爲函數,應該返回一個對象,該對象的每一個鍵值對都是一個映射,定義了 UI 組件的參數怎樣發出 Action
const mapDispatchToProps = ( dispatch, ownProps ) => { return { onClick: () => { dispatch({ type: 'SET_VISIBILITY_FILTER', filter: ownProps.filter }); } }; }
mapDispatchToProps
是一個對象,鍵名是對應 UI 組件的同名參數,鍵值應該是一個函數,會被看成 Action creator ,返回的 Action 會由 Redux 自動發出
const mapDispatchToProps = { onClick: (filter) => { type: 'SET_VISIBILITY_FILTER', filter: filter }; }
3、原理與流程
爲了讓子組件可以得到context屬性,React強制要求根組件(此處爲Provider組件)提供getChildContext實例方法,以及類屬性childContextTypes。而子組件想要獲取context,也必須定義類級別的Counter. contextTypes屬性。定義是雙向的,若是缺乏了任何一塊,子組件都獲取不到context屬性。
我認爲父組件的那塊定義是在Provider的代碼中實現的,而子組件的那部分是在connect方法中實現的。
所以connect方法爲Counter組件添加的context屬性實質上是由Provider傳下來的,這樣在mapStatesToProps方法裏的state參數實質上就是this.context.store.getState()方法得到的。
頁面首次加載以及以後有互動行爲以後整個邏輯的流程:
(1)頁面首次加載時,store裏的初始state獲取過程:
createStore(reducers,defaultParams)的調用,其中reducers可使一個reducer,也但是redux.combineReducers過的reducer的集合。
createStore方法會對每一個reducer去dispatch一個action.type=@@redux/INIT類型的action,而這個action通常在reducer的代碼裏不會被handle,直接掉入default塊,因而就返回了state的初始狀態。
而後通常就會ReactDom.render()將應用渲染出來,每一個子組件的容器組件經過傳入this.context.store.getState()方法得到的state對象, 以及容器組件上自帶的ownProps給mapStatesToProperties方法,來構建props,最後將props應用到子組件的UI組件上。
(2)互動行爲以後整個邏輯:
當在子組件上發生交互行爲,如click時,mapDispatchToProps會定義click觸發時應該dispatch哪個action的映射。而後store接收到這個action後會進行reduce,獲得最新的state,而後再調用全部的子組件的mapStatesToProps方法生成新的props。最後對Provider進行從新渲染。固然上面的事件計算出來的不少state可能都不會發生變化,因此diff算法不會去修改這些沒有發生變化的組件,所以性能也比較好。