view -> actionCreator -> action -> reducer -> newState -> container component
但是,在大多数的前端业务场景中,需要和后端产生异步交互,譬如:网络api的请求。
Redux中怎么来实现异步的数据流呢?
通常我们创建的Action如下:
export const REQUEST_POSTS = 'REQUEST_POSTS' export function requestPosts(subreddit) { return { type: REQUEST_POSTS, subreddit } }
export function fetchPosts(subreddit) { return function (dispatch) { dispatch(requestPosts(subreddit)) return fetch(`http://a.com/xxx`) .then(response => response.json()) .then(json => // 可以多次 dispatch! dispatch(receivePosts(subreddit, json)) ).catch(error){ } } }在异步Action中,我们diapatch了一个requestPosts 的Action,同时根据fetch的结果,dispatch了不同的Action。
实际上,异步Action返回的是一个function。
当 action creator 返回函数时,这个函数会被 Redux Thunk middleware 执行。
这个函数并不需要保持纯净;它还可以带有副作用,包括执行异步 API 请求。这个函数还可以 dispatch action,就像 dispatch 前面定义的同步 action 一样。
Middleware提供的是位于 action 被发起之后,到达 reducer 之前的扩展点。 你可以利用 Redux middleware 来进行日志记录、创建崩溃报告、调用异步接口或者路由等等。
一个 middleware 的结构 ,其核心的部分为
function(action) { // 调用后面的 middleware next(action) }middleware 完全掌控了 reducer 的触发时机, 也就是 action 到了这里完全由中间件控制,不乐意就不给其他中间件处理的机会,而且还可以控制调用其他中间件的时机。
给个例子:
const logger = store => next => action => { if(typeof action === 'function') console.log('dispatching a function'); else console.log('dispatching', action); let result = next(action); console.log('next state', store.getState()); return result; }
其实目前已经有很多第三方 redux 组件支持异步 action,其中如:
redux-thunk 是 redux 官方文档中用到的异步组件,实质就是一个 redux 中间件,thunk 听起来是一个很陌生的词语,先来认识一下什么叫 thunk
A thunk is a function that wraps an expression to delay its evaluation.
简单来说一个 thunk 就是一个封装表达式的函数,封装的目的是延迟执行表达式
// 1 + 2 立即被计算 = 3 let x = 1 + 2; // 1 + 2 被封装在了 foo 函数内 // foo 可以被延迟执行 // foo 就是一个 thunk let foo = () => 1 + 2;
我们来看一下redux-thunk的源码:
function createThunkMiddleware(extraArgument) { return function (_ref) { var dispatch = _ref.dispatch; var getState = _ref.getState; return function (next) { return function (action) { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; }; }; } var thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware; exports['default'] = thunk;
如果 action 也就是一个 thunk,执行 action 相当于执行了异步逻辑action(dispatch, getState, ...)
action 中执行 dispatch,开始新的 redux 数据流,重新回到最开始的逻辑(thunk 可以嵌套的原因)
把执行的结果作为返回值直接返回,直接返回并没有调用其他中间件,也就意味着中间件的执行在这里停止了
如果不是函数直接调用其他中间件并返回。
参考:https://zhuanlan.zhihu.com/p/21398212
http://cn.redux.js.org/docs/advanced/AsyncActions.html