[譯]在 Redux 中使用 AJAX 輪詢(二):Saga 篇

不久以前我寫了一篇關於在 React 中使用 AJAX 輪詢的短文,內容能夠歸納爲如何發起和控制週期性 AJAX 請求。文中我證實了經過使用組件生命週期方法,原生 React 和 Redux 在技術上就足以解決 AJAX 輪詢的控制問題。隨着時間推移,在使用中我發現這個方法須要開發者很是細心地篩選和管理 componentWillReceiveProps 中傳入的 props 。最終,個人目標變成了儘量地清除組件中的異步邏輯。html

在 Redux 生態中,已有很多管理反作用(side effect)的類庫,從最基礎的 redux-thunk,到受 Elm 薰陶的 redux-loop,最後還有使用 Generator 函數強力驅動的 redux-saga前端

理想狀況下,我喜歡把全部的異步請求都放置到一個 API 中間件中,這種用法能夠參考 Redux 官方實例 real-world example。若使用 thunk 會使個人 Action 建立函數被異步邏輯所污染,因此 redux-thunk 已然出局。使用 redux-loop 則會與個人中間件相沖突,做爲 store 的一個 enhancer 它卻修改了 store 的 signature,進而致使其下游的全部中間件都須要調整。因此綜上我決定探索 redux-saga,它本質上提供給個人是在應用後臺執行任務的能力。使用 redux-saga 能夠保證我利用中間件集中控制異步邏輯的用法不變,同時經過設定各種不一樣的觀察者(watcher)來觸發反作用。那麼如何使用 redux-sage 處理 AJAX 輪詢呢?react

// 延時反作用的工具函數
function delay(millis) {  
    const promise = new Promise(resolve => {
        setTimeout(() => resolve(true), millis)
    });
    return promise;
}

// 每隔 20 秒獲取一次數據                                           
function* pollData() {  
    try {
        yield call(delay, 20000);
        yield put(dataFetch());
    } catch (error) {
        // 取消異常 -- 若是你願意也能夠捕獲
        return;
    }
}

// 等待上一次數據請求返回成功後,發起下一輪輪詢
// 若是用戶登出,則取消本次未完成的輪詢                                          
function* watchPollData() {  
    while (true) {             
        yield take(DATA_FETCH_SUCCESS);
        yield race([
            call(pollData),
            take(USER_LOGOUT)
        ]);
    }
}

// 讓各種任務在後臺並行運行                       
export default function* root() {  
    yield [
        fork(watchPollData)
        // 此處可包含其餘觀察者
    ];
}
複製代碼

這種以 sagas 存在的輪詢邏輯讓開發者免於處理組件中潛在的複雜生命週期。我在 race 條件中添加了 USER_LOGOUT Action,這樣能夠代勞以前 componentWillUnmountclearTimeout 的工做。當發送 logout Action 後,運行中的 pollData saga 就能夠被很好地中斷執行。android

其他涉及到的邏輯以下:ios

dataFetch -- 它是一個 Action 建立函數,產生的 Action 會被 API 中間件攔截並處理。在中間件中會發起真正的 API 請求,並根據請求結果發出一系列後續 Action。git

watchPollData -- 它是一個隨應用啓動並一直運行的 saga。啓動後它會阻塞 saga 執行並監聽 DATA_FETCH_SUCCESS Action 的發出。一旦監聽到相應的 Action 被髮出,它就解除阻塞繼續執行後續的 pollData saga。github

pollData -- 先阻塞 Generator 函數的執行,20秒後再調用 dataFetch 並 dispatch dataFetch 產生的 Action。ajax

此處用到的 takeputracecallfork 做用符,均可以在 redux-saga documentation 中找到。redux

你能夠將本文的新方法與前一篇文章中在組件內作控制的方法做比較,使用 saga 後更利於預測和集中管理個人反作用。須要注意的是並非全部的瀏覽器都支持 Generator 函數,若是你使用了 ES2015 和 Babel,那麼它們已經提供了 Generator 函數的瀏覽器 polyfill 兼容支持。後端

如今全部的數據容器(組件)只需在掛載的時候簡單地調用一次 dataFetch() 便可,以後咱們的 saga 就會自動接管全部的輪詢工做。很是簡而美吧。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索