redux-thunk
https://github.com/reduxjs/redux-thunk
Why Do I Need This?
Thunks are the recommended middleware for basic Redux side effects logic, including complex synchronous logic that needs access to the store, and simple async logic like AJAX requests.
Motivation
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
andgetState
as parameters.
相对于同步action, 修改state场景, 对于异步场景, 或者 复杂的同步场景, 就需要thunk中间件。
thunk中间件允许actionCreator返回的dispatch的对象, 不再试普通对象的action(包括type 和 payload参数),
而是一个函数,函数入参为 dispatch 和 getState , 在此函数中处理异步调用 或者 复杂条件的 处理。
异步请求的例子:
const INCREMENT_COUNTER = ‘INCREMENT_COUNTER‘; function increment() { return { type: INCREMENT_COUNTER }; } function incrementAsync() { return dispatch => { setTimeout(() => { // Yay! Can invoke sync or async actions with `dispatch` dispatch(increment()); }, 1000); }; }
条件dispatch例子:
function incrementIfOdd() { return (dispatch, getState) => { const { counter } = getState(); if (counter % 2 === 0) { return; } dispatch(increment()); }; }
给store添加thunk中间件
import { createStore, applyMiddleware } from ‘redux‘; import thunk from ‘redux-thunk‘; import rootReducer from ‘./reducers/index‘; // Note: this API requires redux@>=3.1.0 const store = createStore( rootReducer, applyMiddleware(thunk) );
dispatch a thunk action:
function fetchSecretSauce() { return fetch(‘https://www.google.com/search?q=secret+sauce‘); } function makeASandwichWithSecretSauce(forPerson) { // Invert control! // Return a function that accepts `dispatch` so we can dispatch later. // Thunk middleware knows how to turn thunk async actions into actions. return function (dispatch) { return fetchSecretSauce().then( sauce => dispatch(makeASandwich(forPerson, sauce)), error => dispatch(apologize(‘The Sandwich Shop‘, forPerson, error)) ); }; } // Thunk middleware lets me dispatch thunk async actions // as if they were actions! store.dispatch( makeASandwichWithSecretSauce(‘Me‘) );
dispatch返回结果实际上是一个promise,可以使用 then语句观察结果:
// It even takes care to return the thunk’s return value // from the dispatch, so I can chain Promises as long as I return them. store.dispatch( makeASandwichWithSecretSauce(‘My partner‘) ).then(() => { console.log(‘Done!‘); });
什么是thunk?
https://github.com/reduxjs/redux-thunk
thunk就是一个函数包裹了一个表达式, 表达式延迟执行。
What’s a thunk?!
A thunk is a function that wraps an expression to delay its evaluation.
// calculation of 1 + 2 is immediate // x === 3 let x = 1 + 2; // calculation of 1 + 2 is delayed // foo can be called later to perform the calculation // foo is a thunk! let foo = () => 1 + 2;The term originated as a humorous past-tense version of "think".
https://en.wikipedia.org/wiki/Thunk#cite_note-1
一段程序,不立刻执行, 而是在真正使用的地方, 才计算其值。
相关术语:
call by name
lazy evaluation
表现形式为, 使用匿名函数封装, 等待调用执行任务。
In computer programming, a thunk is a subroutine used to inject an additional calculation into another subroutine. Thunks are primarily used to delay a calculation until its result is needed, or to insert operations at the beginning or end of the other subroutine. It can simply be thought of as a function that takes no arguments, waiting to be called upon to do its work. They have a variety of other applications in compiler code generation and modular programming.
如下面的例子: hypot(3, 4)语句计算比较耗时,将其封装为匿名函数, 在使用的地方调用匿名函数,就相当于执行hypot(3, 4)。
// ‘hypot‘ is a function that returns another function which is already closed over all required data const hypot = (x, y) => () => Math.sqrt(x * x + y * y); // ‘thunk‘ is a function that takes no arguments and performs a potentially expensive operation (computing a square root, in this example) and/or causes some side-effect to occur const thunk = () => hypot(3, 4); // the thunk can then be passed around... doSomethingWithThunk(thunk); // ...or evaluated thunk(); // === 5
如下wiki描述, thunk为最早使用在ada语言的执行上, 当其执行时候, 对于函数参数的类型, 其实可以在编译的时候通过一些思考(thought)确定, 这个确定的过程, 被称为thunk。
增加编译时候的一点点小时间, 从而提高解释时候的效率, 减少时间, 这个类型推断的过程, 如果在执行阶段执行, 那么会被多次执行; 如果每次执行都是一样结果, 那么完全没有必要多次执行,
在编译时候确定(thought), 或者在过程的第一次执行后确定(thought),进而被缓存起来,可以被多次使用。
这种过程的形式被固化下来,并被推广到其它应用场景, 并被命名为thunk。
Eric Raymond rejects "a couple of onomatopoeic myths circulating about the origin of this term" and cites the inventors of the thunk recalling that the term "was coined after they realized (in the wee hours after hours of discussion) that the type of an argument in Algol-60 could be figured out in advance with a little compile-time thought [...] In other words, it had ‘already been thought of‘; thus it was christened a thunk, which is ‘the past tense of "think" at two in the morning‘. See: Raymond, Eric S. (1996). Raymond, Eric S., ed. The New Hacker‘s Dictionary. MIT Press. p. 445. ISBN 9780262680929. Retrieved 2015-05-25.
http://www.ruanyifeng.com/blog/2015/05/thunk.html
编译器的"传名调用"实现,往往是将参数放到一个临时函数之中,再将这个临时函数传入函数体。这个临时函数就叫做 Thunk 函数。
function f(m){ return m * 2; } f(x + 5); // 等同于 var thunk = function () { return x + 5; }; function f(thunk){ return thunk() * 2; }
上面代码中,函数 f 的参数 x + 5 被一个函数替换了。凡是用到原参数的地方,对 Thunk 函数求值即可。
这就是 Thunk 函数的定义,它是"传名调用"的一种实现策略,用来替换某个表达式。
为什么要使用redux-thunk?
如下图,阮老师的文章描述, redux框架,将应用分为 action reducer view三个部分,
对于异步获取数据, 或者添加条件过滤数据场景, 这个过程,在view(react.componet)中实现是不合适, 因为其只负责视图展示,
放在reducer中不行了, 因为框架规定reducer只能作为纯函数使用,
这个重任只能交给 action, 实现 thunk action来做中间层逻辑,此逻辑对数据获取和数据更新到状态负责, 术语 redux store的数据管理和维护的范围。
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_two_async_operations.html
Action 发出以后,过一段时间再执行 Reducer,这就是异步。
怎么才能 Reducer 在异步操作结束后自动执行呢?这就要用到新的工具:中间件(middleware)。
原文地址:https://www.cnblogs.com/lightsong/p/10428627.html