这篇文章主要来看下两个用的最多的函数背后的原理,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复制代码