redux-thunk的一点认识

redux-thunk是什么东西

在此之前先回顾下redux的工作流程:action-> dispatcher -> reducer -> store tree changed -> relative components re-render -> UI changed。这整个过程都是同步的,只要action被dispatch到reducer,对应state发生变化,UI就立即更新。那需要异步访问服务器的场景该怎么办呢?比如我的store上的某些数据需要从服务器上取,取完之后才能dispatch对应的action。所以我们需要在action对象disptach到reducer之前就应该完成必要的异步过程。

Redux提供了thunk这种解决方法,那么thunk又是什么东西呢?看下redux-thunk的github上的解释:

A thunk is a function that wraps an expression to delay its evaluation.

thunk是一个包裹着一个表达式以延迟其求值的函数。

同时举了个例子:

// 表达式1 + 2会被立即计算出来
// x === 3
let x = 1 + 2;

// 包裹在foo这个函数里作为返回值时
// 表达式1 + 2只在函数foo执行的时候才会被计算
// foo就是一个thunk,它延迟了1 + 2的执行
let foo = () => 1 + 2;

redux-thunk也是这样一个函数,对于redux-thunk而言它所谓延迟求值的是指的什么呢?我们上面说到redux里action创建出来到被dispacth到reducer的过程是同步的,我们要实现异步的action就必须延迟action对象的dispatch,这就是对redux-thunk而言所谓的延迟求值。

再结合github上的介绍:

Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods dispatch and getState as parameters.

Redux Thunk中间件允许我们写一个返回function而非action对象的action creators。Redux Thunk可以用来延迟dispatch一个action或者只在某些特定场景下才dispatch。内部函数接受store的dispatch方法和getState方法作为参数。

这里中间件是什么,还是看下文档

It provides a third-party extension point between dispatching an action, and the moment it reaches the reducer. People use Redux middleware for logging, crash reporting, talking to an asynchronous API, routing, and more.

试着翻译一下:
Redux的中间件在dispatch action和action对象到达reducer之前提供了一个第三方扩展点(什么鬼?原谅我只会google翻译)。我们可以用redux中间件来做一些诸如日志记录、创建崩溃报告、调用异步接口或者路由之类的事。

好吧,我感性的理解下:Redux里的中间件是这样的一个东西,这个东西加在dispatch action和action到达reducer这个过程之间,加了有了它之后呢,redux的功能就比不加它强了,可以dispatch函数形式的action了,当然,加的功能都应该定义在这个函数里。比如redux-thunk这个中间件加强的功能就是,在dispatch真正传给reducer的action对象之前允许你去做一些异步操作,异步操作结束后再把真正的action对象dispatch出去;再比如上面说的有着日志记录功能的中间件,这个中间件在dispatch action对象前后打印一些日志信息。

然后借用《深入浅出React和Redux》P183里对中间件特点的总结:

  • 中间件是独立的函数(记住这点很重要,它不是什么很稀奇古怪的东西,就是一个函数,只不过这个函数能处理函数类型的action)
  • 中间件可以组合使用(这个应该很容易接受,不可能只用一个中间件让它去做所有事情)
  • 中间件有一个统一的接口(没有统一接口的话组合使用的难度应该会比较大)

好了,这下可以说清除redux-thunk是个什么东西了:首先redux-thunk(前文用redux-thunk的地方指的应高都是Redux Thunk)指的是一个npm包,这个npm包提供了Redux Thunk这个中间件,这个中间件允许我们在dispatch action对象到reducer之前做一些异步操作。

搞清楚它是什么,有什么用之后,我们需要知道它怎么起作用的,这个“它”指的是Redux Thunk,就不再把它和redux-thunk混为一谈了

Redux Thunk原理是什么

直接上源码(哈哈,每论及源码的时候总感觉好霸气的样子):

function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next =>action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }
    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

看它的默认导出,const thunk = createThunkMiddleware()
thunk是一个函数,这个函数为createThunkMiddleware()的返回值,即第二行return后面的内容。

同时由thunk.withExtraArgument = createThunkMiddleware可知thunk还有一个方法,这个方法指向最外层的那个函数,用于传入额外参数的情况,目前我用到的都是不用传参的情况,那这部分暂时不去理会。

继续说thunk这个函数,如前所述,它以dispatch和getStore为参数,返回值依然是一个函数,记为函数1,函数1以next作为参数,由后面next(action)可知这个next依然是一个函数,函数1的返回值还是一个函数,记为函数2,函数2才是实际起作用的关键,前面的一堆操作暂时可以理解为花架子(当然我知道实际上并不是,涉及到函数式编程的思想),我们具体看函数2:

action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }
    return next(action);
  };

处理逻辑很简单:如果传过来的action类型是函数就传入dispatch, getState参数给这个action函数执行之并返回,否则执行next(action),next()函数的作用是把action对象传给下一个action处理者,或为一个中间件或为最终的reducer。因此,知道它的处理机制后我们通过Redux Thunk来执行异步操作(即定义需要异步操作的的action函数)的套路就有了:

export const sampleAsyncAction = () => {
    return (dispatch, getState) => {
        //执行异步操作,然后相机dispatch新的action对象
    }
}

所以一个添加了Redux Thunk中间件的action流程如下:


image.png

关于redux-thunk就说到这了。

另外说下涉及异步操作下的store里的state tree,
此时state tree里的数据可以分为两部分,一为涉及到异步操作(即需要访问服务器进行存取)的部分;一为只涉及同步更新,并不用存储于服务器的部分。这里只用说前者,目前我的理解是,对于那些需要从服务器上读取的数据,我们是不是只需要在依赖这些数据的组件挂载时访问服务器进行获取数据,同时将获取到的数据同步到state tree,后面的话,只要这部分数据不需要改动那么我们便不用再去访问服务器来获取了,直接用state tree上的数据,因为二者的数据是同步的。对于需要改动的数据,我们访问服务器对其进行写操作成功之后也立即将state tree同步更新。那么就是说除了组件挂载时需要访问服务器获得数据之外,如果单单只是为了获取数据而不用进行写操作的话,那我们只用从state tree上获取数据就可以了。是不是这样?

成了?

最后

关于函数式编程:因为想之前有想要去了解redux的中间件到底是如何起作用的,所以去看了compose, applyMiddleare相关部分的源码,虽然内容不多(哪是不多,相比印象中但凡说源码动不动几百上千行的来比简直少到天上去了,貌似这两个加起来就几十行),但是还是看不下去,转头去了解了下函数是编程相关的东西,也是点云里雾里就暂时搁置。对函数式编程的感觉倒是和知乎有个相关问题下面上轮子哥vczh的回答里的有点像:函数式编程在使用的时候的特点就是,你已经再也不知道数据是从哪里来了,每一个函数都是为了用小函数组织成更大的函数,函数的参数也是函数,函数返回的也是函数,最后得到一个超级牛逼的函数,就等着别人用他来写一个main函数把数据灌进去了。

最后,真的佩服阮一峰前辈这样的奉献者,网上找前端相关知识点的教程几乎都能搜到他,前人栽树后人乘凉,希望有一天自己也能成为这样的前人,能栽出些可以让后人乘凉的树,同时也能感染后人去栽树。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容