原文地址 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熟悉的话,你会知道其中有几个重要的概念:actions
、action creators
、reducers
和middleware
。
actions
即普通的对象。就Redux而言,开箱即用的actions
必须是普通的对象,而且其必须含有一个type
属性。除了上述要求,你可以在这个对象中描述任何你需要执行的action
。actions
形式如下:
// 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 多次相同的action
,action 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,否则它就不能起作用了。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/84504.html