读完了胡子大哈的React.js小书后,总结一下对redux的新理解吧,主要是store,connect,reducer,provider等内容的一些浅见。
redux的出现,事实上为了解决状态管理的问题。最直接的问题就是,如何在各个组件之间共享状态(即组件间通讯)。
Provider
redux应对上述问题的解决方案,就是将这些需要共享的状态放置在根组件的context中(类似于全局变量),其子组件都能获取到context。
具体的做法,其实是将Index组件(根组件)包装成Provider组件:
export class Provider extends Component { static propTypes = { store: PropTypes.object, children: PropTypes.any }
static childContextTypes = { store: PropTypes.object }
getChildContext() { return { store: this.props.store } }
render() { return ( <div>{this.props.children}</div> ) } }
|
这个Provider组件,为整个组件树添加了store,任何子组件都能获取到store
<Provider store={ store }> <Index /> </Provider>
|
Store
store算是组件的状态管理器,也是整个redux的核心。
function createStore(reducer) { let state = null const listeners = [] const subscribe = (listener) => listeners.push(listener) const getState = () => state const dispatch = (action) => { state = reducer(state, action) listeners.forEach(listener => listener()) } dispatch({}) return { getState, dispatch, subscribe } }
|
store做的事情包括以下三件:
- getState:用于获取当前的状态
- dispatch:修改状态(reducer),并将事件分发给所有监听器
- subscribe:订阅事件,用它来增加新的监听器
Reducer
reducer由用户自己定义,有两个参数,前者是老状态,后者是一个action。
它做的事情仅仅是:初始化和计算新的state;根据action的信息,reducer修改对应的状态,并返回一个新状态(全新的对象,而不是在老对象上修改)。
举个书中的例子:
const themeReducer = (state, action) => { if (!state) return { themeColor: 'red' } switch (action.type) { case 'CHANGE_COLOR': return { ...state, themeColor: action.themeColor } default: return state } }
|
reducer,按照规定,应该是一个纯函数。
Connect
connect从本质上讲,是一个高阶组件,它的作用可以理解为:
- 子组件通过connect成为高阶组件后,其内部不用再去对context进行读写(降低依赖性)
- 经过connect后,从context的store里面读取到的state/dispatch/props,将会统一以props的状态传入子组件
export const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => { class Connect extends Component { static contextTypes = { store: PropTypes.object }
constructor() { super() this.state = { allProps: {} } }
_updateProps() { const { store } = this.context let stateProps = mapStateToProps ? mapStateToProps(store.getState(), this.props) : {} let dispatchProps = mapDispatchToProps ? mapDispatchToProps(store.dispatch, this.props) : {} this.setState({ allProps: { ...stateProps, ...dispatchProps, ...this.props } }) }
componentWillMount() { const { store } = this.context this._updateProps() store.subscribe(() => this._updateProps()) }
render() { return <WrappedComponent { ...this.state.allProps }/> } }
return Connect }
|