Redux是将整个应用状态存储到到一个地方,称为store 里面保存一棵状态树(state tree) 组件可以派发(dispatch)行为(action)给store,而不是直接通知其它组件 其它组件可以通过订阅store中的状态(state)来刷新自己的视图.
- redux
redux包含三个部分:createStore.js, bindActionCreators, combineReducers.js applyMiddle
createStore: 生成store ==> 暴露出getState() sunscribe() dispatch()方法
bindActionCreators: 用来组合actions
combineReducers:用来搞命名空间的
- react-redux
react-redux包含connect,provider
- 一个react-redux的例子
app.js ---
import React, { Component } from 'react'
import { render } from 'react-dom'
import Router from './router'
import { Provider } from 'react-redux'
import store from './redux'
render(
<Provider store={store}>{Router}</Provider>,
document.querySelector('#root')
)
home.js ---
import React, { Component } from 'react'
import store from '../redux'
import actions from '../redux/actions'
import { connect } from 'react-redux'
class Home extends Component {
constructor(props) {
super(props)
}
handleClick = () => {
this.props.increment()
}
render() {
return (
<div>
Home
<p>{this.props.count}</p>
<button onClick={this.handleClick}>click</button>
</div>
)
}
}
export default connect(
state => state,
actions
)(Home)
源码分析
- bindActionCreator.js
function bindActionCreators(actions, dispatch) {
let newActions = {}
for (let attr in actions) {
newActions[attr] = function() {
dispatch(actions[attr].apply(null, arguments))
}
}
return newActions
}
export default bindActionCreators
- combineReducers.js
import counter from '../reducer/counter'
export function combineReducers(reducers) {
return function(state = {}, action) {
let newState = {}
for (let attr in reducers) {
let reducer = reducers[attr]
newState[attr] = reducer(state[attr], action)
}
return newState // 返回的是那个大对象
}
}
- createStore.js
const createStore = reducer => {
let state
let getState = () => JSON.parse(JSON.stringify(state))
let listeners = []
let dispatch = action => {
state = reducer(state, action)
listeners.forEach(l => {
l()
})
}
let subscribe = listener => {
listeners.push(listener)
return () => {
listeners = listeners.filter(_ => {
_ !== listener
})
}
}
dispatch({type: '@@redux/INIT'})
return {
getState,
subscribe,
dispatch
}
}
export {createStore}
- connect.js
import React, { Component } from 'react'
import propTypes from 'prop-types'
import bindActionCreators from '../redux/bindActionCreators'
export default function(mapStateToProps, mapDispatchToProps) {
return function(WrapedComponent) {
class ProxyComponent extends Component {
static contextTypes = {
store: propTypes.object
}
constructor(props, context) {
super(props, context)
this.store = context.store
this.state = mapStateToProps(this.store.getState())
}
componentWillMount() {
this.unsubscribe = this.store.subscribe(() => {
this.setState(mapStateToProps(this.store.getState()))
})
}
componentWillUnmount () {
this.unsubscribe()
}
render () {
let actions = bindActionCreators(mapDispatchToProps, this.store.dispatch)
return <WrapedComponent {...this.state} {...actions}/>
}
}
return ProxyComponent
}
}