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