在重构 ThemeSwitch 的时候我们发现,ThemeSwitch 除了需要 store 里面的数据以外,还需要 store 来 dispatch

...
// dispatch action 去改变颜色
handleSwitchColor (color) {
const { store } = this.context
store.dispatch({
type: 'CHANGE_COLOR',
themeColor: color
})
}
...

目前版本的 connect 是达不到这个效果的,我们需要改进它。

想一下,既然可以通过给 connect 函数传入 mapStateToProps 来告诉它如何获取、整合状态,我们也可以想到,可以给它传入另外一个参数来告诉它我们的组件需要如何触发 dispatch。我们把这个参数叫 mapDispatchToProps

const mapDispatchToProps = (dispatch) => {
return {
onSwitchColor: (color) => {
dispatch({ type: 'CHANGE_COLOR', themeColor: color })
}
}
}

和 mapStateToProps 一样,它返回一个对象,这个对象内容会同样被 connect 当作是 props 参数传给被包装的组件。不一样的是,这个函数不是接受 state 作为参数,而是 dispatch,你可以在返回的对象内部定义一些函数,这些函数会用到 dispatch 来触发特定的 action

调整 connect 让它能接受这样的 mapDispatchToProps

export const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => {
class Connect extends Component {
static contextTypes = {
store: PropTypes.object
} constructor () {
super()
this.state = {
allProps: {}
}
} componentWillMount () {
const { store } = this.context
this._updateProps()
store.subscribe(() => this._updateProps())
} _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
}
})
} render () {
return <WrappedComponent {...this.state.allProps} />
}
}
return Connect
}

在 _updateProps 内部,我们把store.dispatch 作为参数传给 mapDispatchToProps,它会返回一个对象 dispatchProps。接着把 statePropsdispatchPropsthis.props 三者合并到 this.state.allProps 里面去,这三者的内容都会在 render函数内全部传给被包装的组件。

另外,我们稍微调整了一下,在调用 mapStateToProps 和 mapDispatchToProps 之前做判断,让这两个参数都是可以缺省的,这样即使不传这两个参数程序也不会报错。

这时候我们就可以重构 ThemeSwitch,让它摆脱 store.dispatch

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from './react-redux' class ThemeSwitch extends Component {
static propTypes = {
themeColor: PropTypes.string,
onSwitchColor: PropTypes.func
} handleSwitchColor (color) {
if (this.props.onSwitchColor) {
this.props.onSwitchColor(color)
}
} render () {
return (
<div>
<button
style={{ color: this.props.themeColor }}
onClick={this.handleSwitchColor.bind(this, 'red')}>Red</button>
<button
style={{ color: this.props.themeColor }}
onClick={this.handleSwitchColor.bind(this, 'blue')}>Blue</button>
</div>
)
}
} const mapStateToProps = (state) => {
return {
themeColor: state.themeColor
}
}
const mapDispatchToProps = (dispatch) => {
return {
onSwitchColor: (color) => {
dispatch({ type: 'CHANGE_COLOR', themeColor: color })
}
}
}
ThemeSwitch = connect(mapStateToProps, mapDispatchToProps)(ThemeSwitch) export default ThemeSwitch

光看 ThemeSwitch 内部,是非常清爽干净的,只依赖外界传进来的 themeColor 和 onSwitchColor。但是 ThemeSwitch 内部并不知道这两个参数其实都是我们去 store里面取的,它是 Dumb 的。这时候这三个组件的重构都已经完成了,代码大大减少、不依赖 context,并且功能和原来一样。

下一节:动手实现 React-redux(五):Provider

上一节:动手实现 React-redux(三):connect 和 mapStateToProps

最新文章

  1. Codeforces Round #342 (Div. 2) B. War of the Corporations(贪心)
  2. 有关css伪类visited样式无效的解决方法
  3. java集合中的传值和传引用
  4. BZOJ2780——[Spoj]8093 Sevenk Love Oimaster
  5. mybatis 的 resulttype 和resultMap
  6. java中使用session的一些细节
  7. PHP加密解密函数
  8. leetcode@ [79/140] Trie树应用 Word Search / Word Search II
  9. SESSION会话技术
  10. hihocoder_1014: Trie树(Trie树模板题)
  11. laravel 事件监听
  12. 登录界面输入判断为空的bug
  13. 大白话5分钟带你走进人工智能-第三节最大似然推导mse损失函数(深度解析最小二乘来源)(1)
  14. docker 拷贝镜像文件
  15. Socket/ServerSocket 选项
  16. java中import static和import的区别【转】
  17. Java中的字段和属性
  18. kail linux arp欺骗
  19. Entities、pads、links 实体、垫、链接
  20. PHP获取当前页面的URL地址

热门文章

  1. mpvue——实现点击数组内的某一元素进行置顶(排序第一)操作
  2. html5--6-55 动画效果-关键帧动画
  3. Intel&#174; Media Server Studio Support
  4. 更改ssh远程登录端口.sh
  5. python-day9-进程、线程、协程篇
  6. ML一些零散记录
  7. caffe 入门实例3 fine-turning
  8. auto_ptr智能指针
  9. HTTP错误code大全
  10. Mac系统下的php扩展开发