2017-05-08 33 views
1

在我的應用我有以下代碼重試功能

componentWillUpdate(nextProps) { 
    if(nextProps.posts.request.status === 'failed') { 
    let timer = null; 

    timer = setTimeout(() => { 
     if(this.props.posts.request.timeOut == 1) { 
     clearTimeout(timer); 
     this.props.fetchData({ 
      page: this.props.posts.request.page 
     }); 
     } else { 
     this.props.decreaseTimeOut(); 
     } 
    }, 1000); 
    } 
} 

它的作用是,當API請求時遇到一個錯誤,也許是因爲沒有互聯網連接(如Facebook的如何聊天作品),或者後端出現錯誤,它會在五秒後重試,但需要每隔一秒設置一次setTimeout以更新商店的一部分,即行this.props.decreaseTimeOut();,但是如果計數器已運行因此5秒鐘過去了,if block將運行並重新發送fetchData action

它運行良好,我沒有問題,至少在功能方面,但在代碼設計方面,我知道這是一個side-effect,它不應該在我的反應組件中處理,因爲我我使用了redux-saga(但是我對redux-saga是新手,我今天剛剛學到了),我想將這個功能轉化爲一個傳奇,我還沒有完全理解如何做到這一點,順便提一句,這裏是我的fetchData saga

import { 
    take, 
    call, 
    put 
} from 'redux-saga/effects'; 

import axios from 'axios'; 

export default function* fetchData() { 
    while(true) { 
    try { 
     let action = yield take('FETCH_DATA_START'); 
     let response = yield call(axios.get, '/posts/' + action.payload.page); 
     yield put({ type: 'FETCH_DATA_SUCCESS', items: [...response.data.items] }); 
    } catch(err) { 
     yield put({ type: 'FETCH_DATA_FAILED', timeOut: 5 }); 
    } 
    } 
} 

回答

2

爲您的代碼使用的是終極版,傳奇的delay承諾的侵擾程度較低的事:

catch(err) { 
    yield put({ type: 'FETCH_DATA_FAILED'}); 

    for (let i = 0; i < 5; i++) { 
     yield call(delay, 1000); 
     yield put(/*Action for the timeout/*); 
    } 
} 

但是我重構這樣的代碼:

function* fetchData(action) { 
    try { 
     let response = yield call(axios.get, '/posts/' + action.payload.page); 
     yield put({ type: 'FETCH_DATA_SUCCESS', items:[...response.data.items] }); 
    } catch(err) { 
     yield put({ type: 'FETCH_DATA_FAILED'}); 
     yield put({ type: 'SET_TIMEOUT_SAGA', time: 5 }); 
    } 
    } 
} 

function *setTimeoutsaga(action) { 
    yield put({type: 'SET_STATE_TIMEOUT', time: action.time}); // Action that update your state 
    yield call(delay, 1000); 

    // Here you use a selector which take the value if is disconnected: 
    // https://redux-saga.js.org/docs/api/#selectselector-args 
    const isStillDisconnected = select() 
    if (isStillDisconnected) { 
     yield put({type: 'SET_TIMEOUT_SAGA', time: action.time - 1}); 
} 

function *fetchDataWatchers() { 
    yield takeEvery('FETCH_DATA_START', fetchData); 
    yield takeEvery('SET_TIMEOUT_SAGA', setTimeoutSaga); 

    // You can insert here as many watcher you want 
} 

export default [fetchDataWatchers]; // You will use run saga for registering this collection of watchers 
+0

看起來真棒但我不想使用takeEvery爲我的FETCH_DATA_START,因爲這將允許用戶一次又一次地點擊'提取數據按鈕'發送多個請求,我不想這樣做,我只想發送請求一次一個,所以我用了,是不是很糟糕? –

+0

@ four-eyes-04-04那麼你可以使用'takeLatest'來完成你所需要的功能:) 但無論如何,你的代碼是好的,我只是不喜歡'while true'結構,但是如果你更喜歡那就像我在第一個片段 – rpadovani

+0

中建議的那樣使用'delay'感謝您的建議,我能夠成功實現該功能。 :-) –