這篇文章主要來看下兩個用的最多的函數背後的原理,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複製代碼