在重构 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

动手实现 React-redux(四):mapDispatchToProps的更多相关文章

  1. react+redux教程(四)undo、devtools、router

    上节课,我们介绍了一些es6的新语法:react+redux教程(三)reduce().filter().map().some().every()....展开属性 今天我们通过解读redux-undo ...

  2. react+redux教程(一)connect、applyMiddleware、thunk、webpackHotMiddleware

    今天,我们通过解读官方示例代码(counter)的方式来学习react+redux. 例子 这个例子是官方的例子,计数器程序.前两个按钮是加减,第三个是如果当前数字是奇数则加一,第四个按钮是异步加一( ...

  3. 【原】react+redux实战

    摘要:因为最近搞懂了redux的异步操作,所以觉得可以用react+redux来做一个小小的项目了,以此来加深一下印象.切记,是小小的项目,所以项目肯定是比较简单的啦,哈哈. 项目效果图如图所示:(因 ...

  4. react + redux 完整的项目,同时写一下个人感悟

    先附上项目源码地址和原文章地址:https://github.com/bailicangd... 做React需要会什么? react的功能其实很单一,主要负责渲染的功能,现有的框架,比如angula ...

  5. react + redux 实现幻灯片

    写在前面: 这一篇是我 使用scss + react + webpack + es6实现幻灯片 的进阶篇,效果请点我,将会使用上redux的基础用法,因为一开始没有理解好redux的用法,单纯看文档, ...

  6. React & Redux 的一些基本知识点

    一.React.createClass 跟 React.Component 的区别在于后者使用了ES6的语法,用constructor构造器来构造默认的属性和状态. 1. React.createCl ...

  7. webpack+react+redux+es6开发模式

    一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入 ...

  8. webpack+react+redux+es6

    一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入 ...

  9. React Redux Sever Rendering实战

    # React Redux Sever Rendering(Isomorphic JavaScript) ![React Redux Sever Rendering(Isomorphic)入门](ht ...

  10. [Redux] Generating Containers with connect() from React Redux (VisibleTodoList)

    Learn how to use the that comes with React Redux instead of the hand-rolled implementation from the ...

随机推荐

  1. Spark简单集群搭建

    1. 上传spark-2.2.0-bin-hadoop2.7.tgz安装包到/home/dtouding目录下 2. 解压安装包到/bigdata/目录下,tar –zxvf spark-2.2.0- ...

  2. isMemberOf与isKindOf的区别

    这两个方法常常会困惑我们,它们有什么区别呢? 定义 首先,我们来看看它们的定义. isKindOfClass: 官方解释:Returns a Boolean value that indicates ...

  3. Codeforces Round #346 (Div. 2) E. New Reform

    E. New Reform time limit per test 1 second memory limit per test 256 megabytes input standard input ...

  4. linux 设备驱动程序中的一些关联性思考

    首先,个人感觉设备驱动程序与应用程序中的文件操作隔得有点远,用户空间不论是直接使用系统调用还是库函数都是通过系统调用的接口进入内核空间代码的.但是看过一个博客的分析整个过程,感觉中间层太过麻烦,必须经 ...

  5. Shell 脚本实现 Linux 系统监控

    一.实验介绍 1.1 实验内容 本课程实现 shell 脚本监控系统的各项参数,并可以将脚本加入系统环境中,可以直接在终端里执行.还添加了几个参数,一个脚本可以执行不同的操作. 1.2 知识点 本实验 ...

  6. UIButton常见属性和方法

    一.创建,两种方法: 1. 常规的 initWithFrame UIButton *btn1 = [[UIButton alloc]initWithFrame:CGRectMake(10, 10, 8 ...

  7. 多线程-threading模块

    #coding:utf-8 import threading from time import sleep,ctime #音乐播放器 def music(func): for i in range(2 ...

  8. 实现列表两端完全对其text-aligh:justify 和display:inline-block

    dispaly:inline-block 对于块级元素,在IE8-下是不兼容的,所以一般不要用在这些元素上,可以用在inline元素上:span text-align:justify实现子元素完全对齐 ...

  9. 关于 .dyib 文件

    .dylib 意味着这是一个动态链接库. libz.dylib 是提供zip压缩.解压缩的库. 库的接口请 #import "zlib.h"

  10. Python 函数的参数传递

    C/C++中,传递参数的类型是可以指定的.一般来说,传递参数可以分为两种:值传递和引用传递.对于值传递,参数传递的过程中进行了复制操作,也就是说,在函数中对参数的任何改动都不会影响到传入的变量:对于引 ...