异步数据流

严格的单向数据流是 Redux 架构的核心。这样的设计可以使应用变得更加可预测和更容易理解。所以 Redux 中的数据一般遵循以下 4 个生命周期。

  • 调用store.dispatch(action),启动一个 State 变更操作。
  • Redux 调用传入的 Reducer 函数,返回新的 State。
  • 主 Reducer 将各个子 Reducer 的输出合并为新的 State 树。
  • Redux 将新的 State 树保存在 Store 中。

在默认情况下 Redux 创建的 Store 并没有使用中间件,所以只支持同步数据流。如果要使 Redux 支持异步数据流,必须加入 redux-thunk 或者 redux-promise 等中间件。这些中间件可以使 Store dispatch 除了 Action 以外的其他内容,例如函数和 Promise,从而达到实现异步数据流的目的。但是无论中间使用了那些中间件,整条中间件链中最后一次 dispatch 的 Action 一定是一个普通对象,并使用同步操作。

根据 Redux 的设计理念,Reducer、Action 等位置上都不适合使用中间件,唯一适合使用中间件的位置为store.dispatch()。所以目前的中间件,都是对store.dispatch()进行了改造,在发送 Action 和执行 Reducer 之间添加了其他的功能。

中间件通过 Redux 提供的applyMiddleware()加入到 Store 中的,一般作为createStore()方法的最后一个参数。applyMiddleware()方法可以接受若干中间件作为参数,中间件的出现顺序代表中间件的调用顺序,并且有些中间件是存在次序要求的。

常用中间件 Redux-Thunk 可以支持 Dispatch 函数,并且可以在处理过程中多次 Dispatch。而使用 Redux-Promise 中间件则可以在 Action 中直接返回一个 Promise。

以下示例使用了 Redux-Thunk 和 Redux-Promise 中间件。

import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import reducers from './reducers';

const store = createStore(reducers, applyMiddleware(thunkMiddleware));

// 定义一个Action Creator
const fetchContents = title => (dispatch, getState) => {
  dispatch(fetchContents(title));
  return fetch('url')
    .then(response => response.json())
    .then(json =>
      dispatch({
        type: 'FETCH_CONTENTS',
        payload: json
      })
    );
};

// 直接dispatch即可
store.dispatch(fetchContents('something'));
import { createStore, applyMiddleware } from 'redux';
import promiseMiddleware from 'redux-promise';
import reducers from './reducers';

const store = createStore(reducers, applyMiddleware(promiseMiddleware));

// 定义一个Action Creator
const fetchContents = (dispatch, title) =>
  new Promise((resolve, reject) => {
    dispatch(requestContents(title));
    return fetch('url').then(response => ({
      type: 'FETCH_CONTENTS',
      payload: response.json()
    }));
  });

从以上两个示例中可以看出,无论采用哪种异步方式,最后 Dispatch 的都是非常明确的 Action,并且执行同步操作。