標籤:todo 首次載入 child stop == 必須 active imp component
一、定義與功能
React-Redux 將所有組件分成兩大類:UI 組件(presentational component)和容器組件(container component)
1、UI 組件特徵:
- 只負責 UI 的呈現,不帶有任何商務邏輯
- 沒有狀態(即不使用
this.state
這個變數)
- 所有資料都由參數(
this.props
)提供
- 不使用任何 Redux 的 API
2、容器組件特徵:
- 負責管理資料和商務邏輯,不負責 UI 的呈現
- 帶有內部狀態
- 使用 Redux 的 API
總結:
UI 組件負責 UI 的呈現,容器組件負責管理資料和邏輯。
React-Redux 規定,所有的 UI 組件都由使用者提供,容器組件則是由 React-Redux 自動產生。也就是說,使用者負責視覺層,狀態管理則是全部交給它。
二、使用與方法
1、connect方法 輸入UI組件, 輸出容器組件
React-Redux 提供connect
方法,用於從 UI 組件產生容器組件。
// 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 };}
三、原理與流程
為了讓子組件能夠獲得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一個[email protected]@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演算法不會去修改這些沒有發生變化的組件,因此效能也比較好。
React-Redux 總結