博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Redux源码分析--bindActionCreators篇
阅读量:6836 次
发布时间:2019-06-26

本文共 3815 字,大约阅读时间需要 12 分钟。

这是Redux源码分析系列的第四篇文章,当这篇文章结束之后Redux源码分析系列也该告一段落了。这篇文章主要想谈谈bindActionCreators这个函数的实现原理,为了更好的理解这个函数我会恰当地引入一些应用代码。

1. ActionCreator创建动作

在深入分析源码之前我们先来聊聊ActionCreator。从字面上理解,它是一个动作的创造者,或者说是动作的工厂。如果我们想根据不同的参数来生成不同步长的计数器动作,则可以把工厂函数声明为

const counterIncActionCreator = function(step) {  return {    type: 'INCREMENT',    step: step || 1  }}复制代码

随着业务逻辑越来越复杂,我们可以通过定义更加复杂的工厂函数来生成更多样化的动作类型。

2. bindActionCreator高阶函数

从上述的例子出发,如果我们想生产出不同步长的计数器动作,并分发他们,则需要把代码写成下面这样子

// 为了简化代码我把dispatch函数定义为只有打印功能的函数const dispatch = function(action) {  console.log(action)}const action1 = counterIncActionCreator()dispatch(action1) // { type: 'INCREMENT', step: 1 }const action2 = counterIncActionCreator(2)dispatch(action2) // { type: 'INCREMENT', step: 2 }const action3 = counterIncActionCreator(3)dispatch(action3) // { type: 'INCREMENT', step: 3 }复制代码

可见每次分发动作之前我们都得手动调用counterIncActionCreator来生产相应的动作,这种方式并不是那么的优雅。这个时候我们就可以采用这个文件里面的bindActionCreator工具函数来优化代码了,该函数的源码如下

function bindActionCreator(actionCreator, dispatch) {  return function() {    return dispatch(actionCreator.apply(this, arguments))  }}复制代码

bindActionCreator将会返回一个新函数,这个函数会用自身所接收的参数来调用actionCreator并生成对应动作,并且这个生成的动作将会作为dispatch函数的参数。也就是说我们把

  1. 生成动作
  2. 调度动作

这两个步骤都封装到一个函数里面了,于是便得到了更为优雅的调度过程

...const increment = bindActionCreator(counterIncActionCreator, dispatch)increment() // { type: 'INCREMENT', step: 1 }increment(2) // { type: 'INCREMENT', step: 2 }increment(3) // { type: 'INCREMENT', step: 3 }复制代码

3. bindActionCreators

接下来看看bindActionCreators这个函数,它是bindActionCreator函数的加强版。删掉一些断言语句之后源码如下

export default function bindActionCreators(actionCreators, dispatch) {  if (typeof actionCreators === 'function') { // #1    return bindActionCreator(actionCreators, dispatch) // #2  }  ....  const keys = Object.keys(actionCreators)  const boundActionCreators = {}  for (let i = 0; i < keys.length; i++) {    const key = keys[i]    const actionCreator = actionCreators[key]    if (typeof actionCreator === 'function') { // #3      boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)    }  }  return boundActionCreators}复制代码

代码#1的判断语句是为了做兼容处理,当接收的参数actionCreators为一个函数的时候,则认为它是单一的动作工厂,便在代码#2处直接调用bindActionCreator工具函数来封装调度过程。

另一情况是当actionCreators参数是一个对象的时候,则遍历这个对象。代码#3会判断每个键在原始对象中的值是否是个函数,如果是一个函数则认为它是一个动作工厂,并使用bindActionCreator函数来封装调度过程,最后把生成的新函数以同样的键key存储到boundActionCreators对象中。在函数的末尾会返回boundActionCreators对象。

举个简单应用例子,首先使用一个对象来存储两个事件工厂

const MyActionCreators = {  increment: function(step) {    return {      type: 'INCREMENT',      step: step || 1    }  },  decrement: function(step) {    return {      type: 'DECREMENT',      step: - (step || 1)    }  }}复制代码

然后通过bindActionCreators来封装调度过程,并返回一个新的对象

const dispatch = function(action) {  console.log(action)}const MyNewActionCreators = bindActionCreators(MyActionCreators, dispatch)复制代码

最后我们便可以用新的对象来主导调度过程了

MyNewActionCreators.increment() // { type: 'INCREMENT', step: 1 }MyNewActionCreators.increment(2) // { type: 'INCREMENT', step: 2 }MyNewActionCreators.increment(3) // { type: 'INCREMENT', step: 3 }MyNewActionCreators.decrement() // { type: 'DECREMENT', step: -1 }MyNewActionCreators.decrement(2) // { type: 'DECREMENT', step: -2 }MyNewActionCreators.decrement(3) // { type: 'DECREMENT', step: -3 }复制代码

这种调度方式显然比原始的依次调用的方式更为优雅

// 原始的调度方式dispatch(MyActionCreators.increment()) // { type: 'INCREMENT', step: 1 }dispatch(MyActionCreators.increment(2)) // { type: 'INCREMENT', step: 2 }dispatch(MyActionCreators.increment(3)) // { type: 'INCREMENT', step: 3 }dispatch(MyActionCreators.decrement()) // { type: 'DECREMENT', step: -1 }dispatch(MyActionCreators.decrement(2)) // { type: 'DECREMENT', step: -2 }dispatch(MyActionCreators.decrement(3)) // { type: 'DECREMENT', step: -3 }复制代码

4. 尾声

这篇文章分析了高阶函数bindActionCreators的源码。它并不是什么复杂的函数,然而通过这类高阶函数我们就可以把原来笨重的函数调用过程封装起来,使最终的业务代码更加优雅。

Happy Coding and Writing!!!

转载地址:http://trqkl.baihongyu.com/

你可能感兴趣的文章
我的友情链接
查看>>
rtmp的URL里面mp3:和mp4:是啥意思
查看>>
ZooKeeper伪分布式集群安装
查看>>
防火墙 之 iptables 匹配条件讲解
查看>>
Nginx配置文件详细说明
查看>>
Tomcat远程调试
查看>>
11月第三周.COM增13.8万 ×××域名.XXX减9个
查看>>
Mybatis联合查询
查看>>
awk进阶
查看>>
我的友情链接
查看>>
解锁新姿势 |如何利用配置中心规范构建PaaS服务配置
查看>>
【阿里云总监课第四期】时髦的云原生应用怎么写?
查看>>
摘自ubantuer-Linux防火墙iptables学习笔记(三)iptables命令详解和举例
查看>>
876. Middle of the Linked List - LeetCode
查看>>
fatal error LNK1123: 转换到 COFF 期间失败
查看>>
提升tomcat服务器性能的七条经验
查看>>
访客门禁系统供应商 首选钱林厂家
查看>>
sqlserver安装和简单的使用
查看>>
android客户端访问服务端tomcat
查看>>
VC/MFC Tips
查看>>