這篇文章主要來看下兩個用的最多的函數背後的原理,connect和combineReducers
// connect() 是一個往組件注入redux相關屬性的函數 // 你能夠注入數據和(經過分發action去改變數據的)回調函數 function connect(mapStateToProps, mapDispatchToProps) { // 經過這一層閉包,它實現了讓咱們在最後一步注入組件的能力,這樣的設計讓你們能夠把它當成decorator使用 return function (WrappedComponent) { // 返回一個組件,這個結構即react提過的HOC return class extends React.Component { render() { return ( <WrappedComponent {/* 父組件傳入的props */} {...this.props} {/* Redux store經過map*函數計算出的props */} {...mapStateToProps(store.getState(), this.props)} {...mapDispatchToProps(store.dispatch, this.props)} /> ) } componentDidMount() { // 一旦組件鏈接上store,它會幫你subscribe,因此你的組件不會錯過任何狀態更新 this.unsubscribe = store.subscribe(this.handleChange.bind(this)) } componentWillUnmount() { // 卸載時幫你註銷訂閱 this.unsubscribe() } handleChange() { // store更新以後從新繪製 this.forceUpdate() } } } } // 這不是真正源碼,而是一個簡化版的模型. // 它跳過了‘store從哪來’的問題 (答案: <Provider> 把它放進了React上下文) // 也跳過了性能優化的問題 (真正的connect()確保了不會作無心義的重繪). // connect() 的目的就是讓你沒必要考慮訂閱store或性能優化,而是如何獲得你想要的狀態state // 使用例子 const ConnectedCounter = connect( // 回調函數拿到state返回prop state => ({ value: state.counter, }), // 回調函數拿到dispatch函數,返回包含dispatch的回調函數 dispatch => ({ onIncrement() { dispatch({ type: 'INCREMENT' }) } }) )(Counter)複製代碼
reducers太多的時候,咱們可能想把他們按照相關性分開,便於管理,在最後用combineReducers在合在一塊兒就行。看下面沒用這個函數的例子javascript
function todos(state = [], action) { switch (action.type) { case ADD_TODO: return [ ...state, { text: action.text, completed: false } ] case TOGGLE_TODO: return state.map((todo, index) => { if (index === action.index) { return Object.assign({}, todo, { completed: !todo.completed }) } return todo }) default: return state } } function visibilityFilter(state = SHOW_ALL, action) { switch (action.type) { case SET_VISIBILITY_FILTER: return action.filter default: return state } } function todoApp(state = {}, action) { return { visibilityFilter: visibilityFilter(state.visibilityFilter, action), todos: todos(state.todos, action) } }複製代碼
其實真相已經不言而喻了,最後的todoApp就等價於combineReducersjava
import { combineReducers } from 'redux' const todoApp = combineReducers({ visibilityFilter, todos }) export default todoApp複製代碼