Redux 是「React 全家桶」中极为重要的一员,它试图为 React 应用提供「可预测化的状态管理」机制。
Redux 本身足够简单,除了 React,它还能够支持其他界面框架。所以如果要将 Redux 和 React 结合起来使用,就还需要一些额外的工具,其中最重要的莫过于 react-redux 了。

react-redux 提供了两个重要的对象,
 Provider 和 connect ,
前者使 React 组件可被连接(connectable),后者把 React 组件和 Redux 的 store 真正连接起来。
react-redux 的文档中,对 connect 的描述是一段晦涩难懂的英文,在初学 redux 的时候,我对着这段文档阅读了很久,都没有全部弄明白其中的意思(大概就是,单词我都认识,连起来啥意思就不明白了的感觉吧)。

在使用了一段时间 redux 后,本文尝试再次回到这里,

预备知识

首先回顾一下 redux 的基本用法。如果你还没有阅读过 redux 的文档,你一定要先去 阅读一下

通过 reducer 创建一个 store ,每当我们在 store 上 dispatch 一个 action , store 内的数据就会相应地发生变化。

我们当然可以 直接 在 React 中使用 Redux:在最外层容器组件中初始化 store ,然后将 state 上的属性作为 props 层层传递下去。

class App extends Component{

  componentWillMount(){
store.subscribe((state)=>this.setState(state))
} render(){
return <Comp state={this.state}
onIncrease={()=>store.dispatch(actions.increase())}
onDecrease={()=>store.dispatch(actions.decrease())}
/>
}
}

但这并不是最佳的方式。最佳的方式是使用 react-redux 提供的 Provider 和 connect 方法。

使用 react-redux

首先在最外层容器中,把所有内容包裹在 Provider 组件中,将之前创建的 store 作为 prop传给 Provider 。

const App = () => {
return (
<Provider store={store}>
<Comp/>
</Provider>
)
};

Provider 内的任何一个组件(比如这里的 Comp ),如果需要使用 state 中的数据,就必须是「被 connect 过的」组件——使用 connect 方法对「你编写的组件( MyComp )」进行包装后的产物。

class MyComp extends Component {
// content...
} const Comp = connect(...args)(MyComp);

可见, connect 方法是重中之重。

connect 详解

究竟 connect 方法到底做了什么,我们来一探究竟。

首先看下函数的签名:

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])

connect() 接收四个参数,它们分别是 mapStateToProps , mapDispatchToProps , mergeProps 和 options 。

mapStateToProps(state, ownProps) : stateProps

这个函数允许我们将 store 中的数据作为 props 绑定到组件上。

const mapStateToProps = (state) => {
return {
count: state.count
}
}

这个函数的第一个参数就是 Redux 的 store ,我们从中摘取了 count 属性。因为返回了具有 count 属性的对象,所以 MyComp 会有名为 count 的 props 字段。

class MyComp extends Component {
render(){
return <div>计数:{this.props.count}次</div>
}
} const Comp = connect(...args)(MyComp);

当然,你不必将 state 中的数据原封不动地传入组件,可以根据 state 中的数据,动态地输出组件需要的(最小)属性。

const mapStateToProps = (state) => {
return {
greaterThanFive: state.count > 5
}
}

函数的第二个参数 ownProps ,是 MyComp 自己的 props 。有的时候, ownProps 也会对其产生影响。比如,当你在 store 中维护了一个用户列表,而你的组件 MyComp 只关心一个用户(通过 props 中的 userId 体现)。

const mapStateToProps = (state, ownProps) => {
// state 是 {userList: [{id: 0, name: '王二'}]}
return {
user: _.find(state.userList, {id: ownProps.userId})
}
} class MyComp extends Component { static PropTypes = {
userId: PropTypes.string.isRequired,
user: PropTypes.object
}; render(){
return <div>用户名:{this.props.user.name}</div>
}
} const Comp = connect(mapStateToProps)(MyComp);

当 state 变化,或者 ownProps 变化的时候, mapStateToProps 都会被调用,计算出一个新的 stateProps ,(在与 ownProps merge 后)更新给 MyComp 。

这就是将 Redux store 中的数据连接到组件的基本方式。

mapDispatchToProps(dispatch, ownProps): dispatchProps

connect 的第二个参数是 mapDispatchToProps ,它的功能是,将 action 作为 props 绑定到 MyComp 上。

const mapDispatchToProps = (dispatch, ownProps) => {
return {
increase: (...args) => dispatch(actions.increase(...args)),
decrease: (...args) => dispatch(actions.decrease(...args))
}
} class MyComp extends Component {
render(){
const {count, increase, decrease} = this.props;
return (<div>
<div>计数:{this.props.count}次</div>
<button onClick={increase}>增加</button>
<button onClick={decrease}>减少</button>
</div>)
}
} const Comp = connect(mapStateToProps, mapDispatchToProps)(MyComp);

由于 mapDispatchToProps 方法返回了具有 increase 属性和 decrease 属性的对象,这两个属性也会成为 MyComp 的 props 。

如上所示,调用 actions.increase() 只能得到一个 action 对象 {type:'INCREASE'} ,要触发这个 action 必须在 store 上调用 dispatch 方法。 diapatch 正是 mapDispatchToProps 的第一个参数。但是,为了不让 MyComp 组件感知到 dispatch 的存在,我们需要将 increase 和 decrease 两个函数包装一下,使之成为直接可被调用的函数(即,调用该方法就会触发 dispatch)。

Redux 本身提供了 bindActionCreators 函数,来将 action 包装成直接可被调用的函数。

import {bindActionCreators} from 'redux';

const mapDispatchToProps = (dispatch, ownProps) => {
return bindActionCreators({
increase: action.increase,
decrease: action.decrease
});
}

同样,当 ownProps 变化的时候,该函数也会被调用,生成一个新的 dispatchProps ,(在与 statePrope 和 ownProps merge 后)更新给 MyComp 。注意, action 的变化不会引起上述过程,默认 action 在组件的生命周期中是固定的。

[mergeProps(stateProps, dispatchProps, ownProps): props]

之前说过,不管是 stateProps 还是 dispatchProps ,都需要和 ownProps merge 之后才会被赋给 MyComp 。 connect 的第三个参数就是用来做这件事。通常情况下,你可以不传这个参数, connect 就会使用 Object.assign 替代该方法。

其他

最后还有一个 options 选项,比较简单,基本上也不大会用到(尤其是你遵循了其他的一些 React 的「最佳实践」的时候),本文就略过了。希望了解的同学可以直接看文档。

(完)

React 实践心得:react-redux 之 connect 方法详解的更多相关文章

  1. HTTP请求方法详解

    HTTP请求方法详解 请求方法:指定了客户端想对指定的资源/服务器作何种操作 下面我们介绍HTTP/1.1中可用的请求方法: [GET:获取资源]     GET方法用来请求已被URI识别的资源.指定 ...

  2. JAVA 注解的几大作用及使用方法详解

    JAVA 注解的几大作用及使用方法详解 (2013-01-22 15:13:04) 转载▼ 标签: java 注解 杂谈 分类: Java java 注解,从名字上看是注释,解释.但功能却不仅仅是注释 ...

  3. Java提高篇——equals()与hashCode()方法详解

    java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...

  4. for_each使用方法详解[转]

    for_each使用方法详解[转] Abstract之前在(原創) 如何使用for_each() algorithm? (C/C++) (STL)曾經討論過for_each(),不過當時功力尚淺,只談 ...

  5. Android源码下载方法详解

    转自:http://www.cnblogs.com/anakin/archive/2011/12/20/2295276.html Android源码下载方法详解 相信很多下载过内核的人都对这个很熟悉 ...

  6. java基础(十六)----- equals()与hashCode()方法详解 —— 面试必问

    本文将详解 equals()与hashCode()方法 概述 java.lang.Object类中有两个非常重要的方法: public boolean equals(Object obj) publi ...

  7. Python 在子类中调用父类方法详解(单继承、多层继承、多重继承)

    Python 在子类中调用父类方法详解(单继承.多层继承.多重继承)   by:授客 QQ:1033553122   测试环境: win7 64位 Python版本:Python 3.3.5 代码实践 ...

  8. php调用C代码的方法详解和zend_parse_parameters函数详解

    php调用C代码的方法详解 在php程序中需要用到C代码,应该是下面两种情况: 1 已有C代码,在php程序中想直接用 2 由于php的性能问题,需要用C来实现部分功能   针对第一种情况,最合适的方 ...

  9. equals()与hashCode()方法详解

    java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...

随机推荐

  1. 阿里云cenos 6.5 模板上安装 docker

    本章将介绍在阿里云的 Centos6.5 模板上安装 Docker 以及在 Ubuntu 14.04 模板上安装 Docker 的过程 Centos 6.5 模板上使用Docker 首先,通过 ssh ...

  2. 32位与4G内存限制

    32位有4G内存限制,好像人所共知.但这个32位是指32位的CPU还是32位的操作系统? 答案是,都是.内存限制,是操作系统和硬件(CPU,也许还有内存控制器)共同制约的.CPU对应的是寻址物理地址, ...

  3. 程序员的vim

    1,所有的Unix like系统都会内建vi文书编辑器,其他的文书编辑器则不一定会存在,但是目前我们使用比较多的是vim编辑器 vim具有程序编辑的能力,可以主动的以字体颜色辨别语法的正确性,方便程序 ...

  4. iOS开发——高级篇——线程保活

    线程保活: 顾名思义,就是保护线程不死(保证线程处于激活状态,生命周期没有结束) 正常情况,当线程执行完一次任务之后,需要进行资源回收,也就意味着生命周期结束 应用场景: 当有一个任务,随时都有可能去 ...

  5. 显示 目录 大小 du

    [root@hadoop1 /]# du -BG  -d 11G ./boot0G ./dev63G ./homedu: 无法访问"./proc/6689/task/6689/fd/4&qu ...

  6. Mac mysql 运行sql文件中文乱码的问题

    别再傻傻的改什么mysql的编码格式了. 是.sql文件的编码有问题,把sql文件的编码格式改成utf-8就行了. mac怎么修改呢? vscode最爽了. 用vscode打开.sql文件,然后点右下 ...

  7. ZOJ1610 Count the Colors —— 线段树 区间染色

    题目链接:https://vjudge.net/problem/ZOJ-1610 Painting some colored segments on a line, some previously p ...

  8. Silverlight实用示例 - DataGrid行详细信息的绑定DataGrid.RowDetailsTemplate

    Silverlight实用示例 - DataGrid行详细信息的绑定DataGrid.RowDetailsTemplate 2012-12-28 21:04 来源:博客园 作者:chengxingli ...

  9. Python下的LibSVM的使用

    突然觉的笔记真的很重要,给自己省去了很多麻烦,之前在Python 3 中装过libsvm 每一步都是自己百度上面搜寻的,花费了很长时间,但是并没有记录方法.这次换了电脑,又开始重新搜寻方法,觉得太浪费 ...

  10. 【HAOI 2007】 上升序列

    [题目链接] 点击打开链接 [算法] 先预处理 : 将序列反转,求最长下降子序列 对于每个询问,根据字典序性质,贪心即可 [代码] #include<bits/stdc++.h> usin ...