- 原文地址:AJAX POLLING IN REACT WITH REDUX
- 原文作者:Josh M
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:劉嘉一
- 校對者:yoyoyohamapi,FateZeros
更新: 檢視最新關於使用 redux-saga 進行輪詢的文章:notjoshmiller.com/ajax-pollin…
正如生活不總是給予你所需之物,你所用的 API 也不總是支援流式事件。因此,當你需要把一些有時序依賴的狀態從服務端同步到客戶端時,一個常用的 “曲線救國” 方法就是使用 AJAX 進行介面輪詢。我們大部分人都知道使用 setInterval
並不是處理輪詢的 “最佳人選”,不過它的堂兄 setTimeout
配合 遞迴解法 卻可以大展身手。
React & Redux 為我們提供了響應式的資料流,我們如何才能使普通的輪詢方法與其和諧共處?RxJS 以及其他 Observable 類庫是處理輪詢的不錯選擇,不過除非你的專案已經整合了 Observable 類庫,否則僅為解決輪詢而引入相關類庫顯得並不值當。當前通過結合 React 元件的生命週期方法和 Redux 的 Action 就已經足夠處理 AJAX 輪詢,下面來看看如何得解?
首先通過 Redux 的 Reducer 來說明當前 State:
const initialState = {
data: {},
isFetching: false
};
export function data (state = initialState, action) {
switch (action.type) {
case DATA_FETCH_BEGIN: {
return { ...state, isFetching: true };
}
case DATA_FETCH_SUCCESS: {
return { isFetching: false, data: { ...state.data, action.payload }};
}
case DATA_FETCH_ERROR: {
return { ...state, isFetching: false };
}
default:
return state;
}
複製程式碼
我不會在這裡去講解如何處理 Redux 中的非同步 Action 建立函式,想更好地瞭解這方面知識請參考 Redux 文件中的非同步示例。 現在只需假設我們已有相關的 Redux 中介軟體來處理本文提到的各種 Action 。我會使用與 real-world example(譯註:原文連結的倉庫已不存在,可以參考 Redux 文件中同名例子)中相似形式的 Action 建立函式。
對應上方的資料模型,我們的 Action 建立函式可能為:
export function dataFetch() {
return {
[CALL_API]: {
types: [DATA_FETCH_BEGIN, DATA_FETCH_SUCCESS, DATA_FETCH_ERROR],
endpoint: `api/data/`
}
};
}
複製程式碼
回到最初的問題,讓我們想想你會如何實現 API 介面的輪詢。你會把輪詢的定時器設定在 Reducer 中?還是 Action 建立函式裡?或許是中介軟體裡?如果把定時器放到 Smart 元件(譯註:參看 Smart and Dumb Components – Medium)中怎麼樣呢?我會選擇在元件中設定定時器,不僅是因為元件需要控制自身的資料依賴,而且我們可以通過元件的生命週期方法控制這些定時器,看看如何做到?
import React from `react`;
import {connect} from `react-redux`;
import {bindActionCreators} from `redux`;
import * as DataActions from `actions/DataActions`;
// 元件需要哪些 Redux 全域性狀態作為 props 傳入?
function mapStateToProps(state) {
return {
data: state.data.data,
isFetching: state.data.isFetching
};
}
// 元件需要哪些 Action 建立函式作為 props 傳入?
function mapDispatchToProps(dispatch) {
return {
dataActions: bindActionCreators(DataActions, dispatch)
};
}
@connect(mapStateToProps, mapDispatchToProps)
export default class AppContainer {
componentWillReceiveProps(nextProps) {
if (this.props.data !== nextProps.data) {
clearTimeout(this.timeout);
// 你可以在這裡處理獲取到的資料
if (!nextProps.isFetching) {
this.startPoll();
}
}
}
componentWillMount() {
this.props.dataActions.dataFetch();
}
componentWillUnmount() {
clearTimeout(this.timeout);
}
startPoll() {
this.timeout = setTimeout(() => this.props.dataActions.dataFetch(), 15000);
}
}
複製程式碼
好了,大功告成。因為上面的元件需要一些額外資料進行渲染,所以它會在掛載的時候嘗試獲取這些資料。 當 dataFetch
傳送了一個新 Action 後,我們的 Reducer 會返回新的狀態, 進而觸發元件的 componentWillReceiveProps
方法。在這個生命週期方法內會首先清除所有進行中的定時器,若當前沒有進行資料請求則隨即啟動一個新定時器。
誠然還有很多方法可以處理這裡的介面輪詢問題,並且如果有任何長輪詢方法可用時,此處的輪詢方法便相形見絀。不過我還是希望這篇文章可以幫助闡明結合 React 生命週期方法和 Redux 資料流的處 “事” 之道。
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。