redux浅析

读完了胡子大哈的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做的事情包括以下三件:

  1. getState:用于获取当前的状态
  2. dispatch:修改状态(reducer),并将事件分发给所有监听器
  3. 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从本质上讲,是一个高阶组件,它的作用可以理解为:

  1. 子组件通过connect成为高阶组件后,其内部不用再去对context进行读写(降低依赖性)
  2. 经过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) :
{} // 防止 mapStateToProps 没有传入
let dispatchProps = mapDispatchToProps ?
mapDispatchToProps(store.dispatch, this.props) :
{} // 防止 mapDispatchToProps 没有传入
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
}