[译]「thunk」到底是个什么东西

原文地址 What the heck is a 'thunk'?

问:你了解thunk吗?

答:你第一次听说redux-thunk时头皮发麻的声音。

抱歉,这样的回答实在是有点糟糕。 但是,讲真的:如果你之前没有接触过,Redux Thunk 绝对是个令人迷惑的东西。我觉得大部分原因在于 thunk 这个单词吧。那么让我们先把这个单词的意思搞明白吧。

thunk,名词

thunk 是函数(function)的另一种表达方式。但它并不仅仅是传统的函数,而是由其他函数返回的一种特殊且不常见的函数的别称。比如下面这个:

function wrapper_function(){
    // 这个函数就称之为 thunk,它的功能是将任务延迟执行
    return function thunk(){ // 可以是具名函数,也可以匿名
        console.log('do stuff now')
    }
}
复制代码

其实你已经了解过或用过这种模式。只不过你不知道他就叫thunk罢了。如果你想打印do stuff now,只需要执行两次wrapper_function就可以了,即wrapper_function()()

redux-thunk

那么,这种形式的函数又是如何应用到Redux中去的呢? 如果你对Redux熟悉的话,你会知道其中有几个重要的概念:actionsaction creatorsreducersmiddleware

actions即普通的对象。就Redux而言,开箱即用的actions必须是普通的对象,而且其必须含有一个type属性。除了上述要求,你可以在这个对象中描述任何你需要执行的actionactions形式如下:

// 1. 普通对象
// 2. 有一个type属性
// 3. 任何其他你需要的
{
  type: "USER_LOGGED_IN",
  username: "dave"
}
复制代码

由于一直重复的去写这些对象很烦人,于是 Redux 就有了action-creators的概念。

function userLoggedIn() {
  return {
    type: 'USER_LOGGED_IN',
    username: 'dave'
  };
}
复制代码

这个虽然看起来跟前面的action是一样的,但现在方便的是你可以通过调用userLoggedIn函数来生成action了。这样,就对其进行了一次抽象。

现在你可以通过调用函数来创建actions返回对象了,再也不用你去手敲了。这时如果你需要在你的项目中 dispatch 多次相同的actionaction creators就能帮你省很多力气了。

Actions太枯燥了

现在你有没有发现一个有趣的事情,Redux所谓的actions实际上啥都没干。它们就是对象而已,普通、简单又没什么用武之地。

那么如果你真的可以让它们做点什么,那不是很酷吗?比方说,调用一个API,或是触发其他操作?

由于reducers应该是纯函数(不改变任何作用域外的东西),所以我们并不能在一个 reducer 内部调用任何API或者是 dispatch 一个 action

如果你想要让一个action去做点儿什么,那么你的代码应该包含在一个函数内部。这个函数(也即 thunk)是一系列将来才会完成的操作。

要是action creators可以完成这样的功能那就太棒了。它会返回我们需要的一系列将来会被执行的动作,而不是简单的对象。比如下面这样:

function getUser() {
  return function() {
    return axios.get('/current_user');
  };
}
复制代码

现在好了,redux-thunk确实就是干这个的。它就是个中间件,去监控传入系统中的每一个action,如果是个函数的话,那么它就会调用那个函数。这就是redux-thunk的职责。

在上面的示例中,我唯一漏掉的一点就是Redux会传递两个参数给thunk函数:dispatch - 如果需要的话可以 dispatch 新的 action;getState - 用于访问当前 state。

function logOutUser() {
  return function(dispatch, getState) {
    return axios.post('/logout').then(function() {
      // 假设我们声明过一个 action creator
      // 叫做 'userLoggedOut', 现在我们可以 dispatch 它了
      dispatch(userLoggedOut());
    });
  };
}
复制代码

再补充一点:getState还可用于决定是获取新数据还是返回缓存结果,这取决于当前 state。 这就是redux-thunk做的事情了。

着实是个很小的库了

redux-thunk库的完整源码都在这了:

function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    // 在这儿调用所有你 dispatch 的 action
    // 如果是个函数的话,直接调用
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    // 否则,继续处理该action
    return next(action);
  };
}

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

export default thunk;
复制代码

在你项目中安装了redux-thunk后,你 dispatch 的每一个 action 都会经过这几行代码的处理。它调用actions为函数的actions(不去管它返回什么),如果actions不是函数,就将其传给下一个中间件或者Redux本身(也就是next(action)这行代码所做的工作)。

在你的项目中使用 redux-thunk

如果你的项目中已经配置好了 Redux,那么添加redux-thunk只需两步:

首先,安装redux-thunk

npm install --save redux-thunk
复制代码

然后,不论你的Redux配置代码在哪儿,你只需引入redux-thunk后把该中间件插入到Redux当中去:

// 你需要引入 appleMiddleware
import { createStore, applyMiddleware } from 'redux';

// 引入 thunk 中间件
import thunk from 'redux-thunk';

// 引入现存的根reducer路径
// 改变该路径以适应你的配置
import rootReducer from './reducers/index';

// createStore 的最后一个参数为「增强store」,
// 这里我们基于 thunk 中间件,使用applyMiddleware来创建该「增强store」
const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);
复制代码

只需确保你正确的调用applyMiddleware时传入了 thunk,否则它就不能起作用了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值