Redux介紹之異步Action

上一篇介紹了中間件,是給本篇做鋪墊用的,可以幫助你理解本篇介紹的異步Action洲拇。前幾篇所有的Action都是同步Action,即本地?cái)?shù)據(jù)塞進(jìn)Action中立即dispatch出去更新state曲尸。但現(xiàn)實(shí)中很多數(shù)據(jù)是需要從服務(wù)器端取的(常見ajax方式取數(shù)據(jù))赋续,因此需要異步Action。本篇的源碼已上傳Github另患,請(qǐng)參照src/reactReduxAsync文件夾纽乱。

其實(shí)Action是個(gè)plan object,不存在同步或者異步的概念昆箕。所謂的異步Action鸦列,本質(zhì)上是一系列Action動(dòng)作:

第一步:先dispatch出請(qǐng)求服務(wù)器數(shù)據(jù)的Action(通常此時(shí)state里會(huì)設(shè)計(jì)個(gè)loading或fetching的值,讓頁面呈現(xiàn)出loading狀態(tài))

第二步:服務(wù)器返回了數(shù)據(jù)(也可返回異常)为严,將數(shù)據(jù)塞入Action里编丘,再dispatch出這個(gè)Action去更新state。

第一步好實(shí)現(xiàn)挽拔,正常dispatch一個(gè)type為request的Action就行了吼拥。第二步也好實(shí)現(xiàn),正常dispatch一個(gè)帶服務(wù)器端數(shù)據(jù)的Action就行了夕吻。關(guān)鍵是如何將第一步和第二步捆綁起來诲锹,執(zhí)行第一步后,進(jìn)入等待狀態(tài)涉馅,自動(dòng)執(zhí)行第二步归园。這也是異步Action的關(guān)鍵,即redux-thunk中間件稚矿。

上一篇介紹過中間件:在Redux里中間件等同于修改Store.dispatch方法庸诱,將其變成洋蔥圈式的強(qiáng)化版Store.dispatch方法。redux-thunk中間件的源碼總共15行晤揣,直接貼出來:

function createThunkMiddleware(extraArgument) {
  return function (_ref) {
    var dispatch = _ref.dispatch,
        getState = _ref.getState;
    return function (next) {
      return function (action) {
        if (typeof action === 'function') {
          return action(dispatch, getState, extraArgument);
        }

        return next(action);
      };
    };
  };
}

閱讀源碼可知桥爽,常規(guī)的Action creator只能返回一個(gè)Action,但有了redux-thunk昧识,你的Action creator還可以返回一個(gè)function(dispatch, getState)钠四。函數(shù)的參數(shù)一看名字就知道是干什么的,不贅述跪楞。目的就是將上述第一步發(fā)送request的Action和第二步發(fā)送取得數(shù)據(jù)后的Action封裝在里面缀去。

entries/reactReduxAsync.js:先在入口處引入redux-thunk

import thunk from 'redux-thunk';

...
const store = createStore(reducer, compose(
    applyMiddleware(thunk, logger),
    window.devToolsExtension ? window.devToolsExtension() : (f) => f,
));

actions/fetchData.js:

import fetch from 'isomorphic-fetch';
import * as constant from '../configs/action';
import { sleep } from '../lib/common';

const requestData = () => ({
    type: constant.REQUEST_DATA,
});

const receiveData = (data) => ({
    type: constant.RECEIVE_DATA,
    data: data.msg,
});

const doFetchData = () => async(dispatch) => {
    dispatch(requestData());
    await sleep(1000);      // Just 4 mock
    return fetch('./api/fetchSampleData.json')
        .then((response) => response.json())
        .then((json) => dispatch(receiveData(json)));
};

const canFetchData = (state) => {
    return !state.fetchData.fetching;
};

export default {
    fetchDataAction: () => (dispatch, getState) => {
        if (canFetchData(getState())) {
            return dispatch(doFetchData());
        }
        return Promise.resolve();
    },
};

解釋一下侣灶,requestData是個(gè)常規(guī)的發(fā)送request請(qǐng)求的Action creator,供第一步用缕碎。receiveData是個(gè)常規(guī)的攜帶數(shù)據(jù)的Action creator褥影,供第二步用。重點(diǎn)在如何將第一步和第二步打包進(jìn)fetchDataAction里阎曹。

fetchDataAction返回的是react-thunk支持的function(dispatch, getState)伪阶,而不是一個(gè)對(duì)象形式的Action。doFetchData里dispatch第一步的request請(qǐng)求的Action处嫌,(中間因?yàn)閿?shù)據(jù)取太快看不出效果栅贴,所以強(qiáng)制讓取數(shù)據(jù)延遲1秒,sleep(1000)這行代碼請(qǐng)無視)熏迹,然后向服務(wù)器fetch數(shù)據(jù)檐薯,取到數(shù)據(jù)后dispatch第二步的攜帶數(shù)據(jù)的Action。

中間插著一個(gè)canFetchData方法是為優(yōu)化用的注暗,當(dāng)正在請(qǐng)求數(shù)據(jù)時(shí)禁止重復(fù)請(qǐng)求數(shù)據(jù)坛缕,防止用戶狂點(diǎn)查詢按鈕,節(jié)省服務(wù)器開銷捆昏,這與本篇內(nèi)容無關(guān)赚楚,可以無視。

代碼雖短骗卜,但里面信息量卻不少宠页,你需要具備中間件Promise寇仓,thunk的知識(shí)举户,ES6的基本語法知識(shí)也不可少。

reducers/fetchData.js:

import * as constant from '../configs/action';
import { createReducer } from '../lib/common';

const initialState = {
    fetching: false,
    data: null,
};

export default createReducer(initialState, {
    [constant.REQUEST_DATA]: (state, action) => {
        return {
            ...state,
            fetching: true,
        };
    },
    [constant.RECEIVE_DATA]: (state, action) => {
        return {
            ...state,
            fetching: false,
            data: action.data,
        };
    },
});

Reducer里只是單純處理數(shù)據(jù)遍烦,沒什么特別的俭嘁。需要注意的是,設(shè)計(jì)了一個(gè)fetching變量服猪,當(dāng)收到第一步request的Action時(shí)供填,將其設(shè)為true,觸發(fā)頁面的loading組件罢猪。當(dāng)收到第二步更新值的Action時(shí)捕虽,將其設(shè)為false,隱藏頁面的loading組件坡脐。

效果如下圖,點(diǎn)擊按鈕后獲取到數(shù)據(jù)房揭,你可以跟著教程自己嘗試一下:


至此Redux教程已經(jīng)結(jié)束备闲,順便把項(xiàng)目的目錄結(jié)構(gòu)也定了:


你可以根據(jù)業(yè)務(wù)需要再加上apis(統(tǒng)一管理服務(wù)器請(qǐng)求)晌端,i18n(多國語目錄),styles(通用的css樣式)恬砂,template目錄(HTML模板咧纠。因?yàn)榻坛逃卸嗥晕覍emplate目錄放到了項(xiàng)目的根目錄下)泻骤。將目錄結(jié)構(gòu)漆羔,和通用方法加入你們項(xiàng)目的腳手架里,這樣就可以規(guī)范react-redux項(xiàng)目的代碼狱掂。

最后演痒,如果覺得教程還行,請(qǐng)不吝嗇Github上star一下趋惨,點(diǎn)這里鸟顺,這個(gè)要求不過分吧 _

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市器虾,隨后出現(xiàn)的幾起案子讯嫂,更是在濱河造成了極大的恐慌,老刑警劉巖兆沙,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件欧芽,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡葛圃,警方通過查閱死者的電腦和手機(jī)千扔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來装悲,“玉大人昏鹃,你說我怎么就攤上這事【髡铮” “怎么了洞渤?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長属瓣。 經(jīng)常有香客問我载迄,道長,這世上最難降的妖魔是什么抡蛙? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任护昧,我火速辦了婚禮,結(jié)果婚禮上粗截,老公的妹妹穿的比我還像新娘惋耙。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布绽榛。 她就那樣靜靜地躺著湿酸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪灭美。 梳的紋絲不亂的頭發(fā)上推溃,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音届腐,去河邊找鬼铁坎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛犁苏,可吹牛的內(nèi)容都是我干的硬萍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼傀顾,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼襟铭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起短曾,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤寒砖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后嫉拐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哩都,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年婉徘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了漠嵌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡盖呼,死狀恐怖儒鹿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情几晤,我是刑警寧澤约炎,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站蟹瘾,受9級(jí)特大地震影響圾浅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜憾朴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一狸捕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧众雷,春花似錦灸拍、人聲如沸做祝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽剖淀。三九已至,卻和暖如春纤房,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背翻诉。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國打工炮姨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人碰煌。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓舒岸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親芦圾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蛾派,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容