2017-08-06 55 views
1

我試圖一次只處理一個給定的ID的下載。我希望它是非阻塞的,所以「不同的文件ID」可以並行下載,這就是爲什麼我在做takeEvery。我想放棄,如果「相同的文件ID」已在進行中。takeEvery,但它是丟棄每一個

一旦行動DOWNLOAD_FILE被派遣,我設置在減速器,file.isDownloading = true。然而downloadFileWorker總是發現它是真實的並且丟棄。

這裏是我的傳奇:

const DOWNLOAD_FILE = 'DOWNLOAD_FILE'; 
export function downloadFile(id) { 
    return { 
     type: DOWNLOAD_FILE, 
     id 
    } 
} 
function* downloadFileWorker(action) { 
    const { id } = action; 

    const state = yield select(); 
    const files = state; 

    const file = files.find(file => file.id === id); 
    if (file.isDownloading) { 
     console.log('discontinuing worker as file is already downloading'); 
     return; 
    } else { 
     console.log('OK CONTINUE TO DOWNLOAD'); 
     const res = yield call(fetch, ...); 
     const json = yield call(res.json); 
     console.log('json:', json); 
    } 
} 
function* downloadFileWatcher() { // i think i can call this downloadFileSaga 
    yield takeEvery(DOWNLOAD_FILE, downloadFileWorker); 
} 

我們在這裏看到這第一個發現在該州的文件,如果它isDownloading那麼它不會繼續(在downloadFileWorker)。

DOWNLOAD_FILE動作被觸發時,在reducer中我將文件設置爲isDownloading,所以我的工作人員總是放棄。這是我的減速器:

export default function reducer(state=INITIAL, action) { 
    switch(action.type) { 
     case DOWNLOAD_FILE: { 
      const { id } = action; 
      const files = state; 
      if (!files) return state; 

      const file = files.find(file => file.id === id); 
      if (!file) return state; 

      if (file.isDownloading) { 
       console.log('discarding reducer action, as file is already downloading'); 
       return state; 
      } 

      return files.map(file => file.id !== id ? file : { ...file, isDownloading:true }) 
     } 
     default: return state; 
    } 
} 

回答

1

這是因爲當動作被分派時總是最先執行減速,然後才傳奇。解決這個問題的一種方法是將流量分成兩個操作。 One - DOWNLOAD_FILE - 開始傳奇,然後第二個 - - DOWNLOAD_FILE_STARTED從佐賀isDownloading是假的,並更新isDownloading狀態時被分派:

const DOWNLOAD_FILE = 'DOWNLOAD_FILE'; 
const DOWNLOAD_FILE_STARTED = 'DOWNLOAD_FILE_STARTED'; 
export function downloadFile(id) { 
    return { 
     type: DOWNLOAD_FILE, 
     id 
    } 
} 
export function downloadFileStarted(id) { 
    return { 
     type: DOWNLOAD_FILE_STARTED, 
     id 
    } 
} 
function* downloadFileWorker(action) { 
    const { id } = action; 

    const state = yield select(); 
    const files = state; 

    const file = files.find(file => file.id === id); 
    if (file.isDownloading) { 
     console.log('discontinuing worker as file is already downloading'); 
     return; 
    } else { 
     console.log('OK CONTINUE TO DOWNLOAD'); 
     yield put(downloadFileStarted(id)); 
     const res = yield call(fetch, ...); 
     const json = yield call(res.json); 
     console.log('json:', json); 
    } 
} 
function* downloadFileWatcher() { // i think i can call this downloadFileSaga 
    yield takeEvery(DOWNLOAD_FILE, downloadFileWorker); 
} 

...

export default function reducer(state=INITIAL, action) { 
    switch(action.type) { 
     case DOWNLOAD_FILE_STARTED: { 
      const { id } = action; 
      const files = state; 
      if (!files) return state; 

      const file = files.find(file => file.id === id); 
      if (!file) return state; 

      if (file.isDownloading) { 
       console.log('discarding reducer action, as file is already downloading'); 
       return state; 
      } 

      return files.map(file => file.id !== id ? file : { ...file, isDownloading:true }) 
     } 
     default: return state; 
    } 
} 

另一種方式接近這一點,如果你想避免第二行動,是要記住當前和以前的行動派遣之間的狀態。

function* downloadFileWorker(action, prevState) { 
    const { id } = action; 

    const files = prevState; 

    const file = files.find(file => file.id === id); 
    if (file.isDownloading) { 
     console.log('discontinuing worker as file is already downloading'); 
     return; 
    } else { 
     console.log('OK CONTINUE TO DOWNLOAD'); 
     const res = yield call(fetch, ...); 
     const json = yield call(res.json); 
     console.log('json:', json); 
    } 
} 
function* downloadFileWatcher() { 
    while (true) { 
     const prevState = yield select(); 
     const action = yield take(DOWNLOAD_FILE); 
     yield fork(downloadFileWorker, action, prevState); 
    } 
} 

prevState不一定正好以前的狀態,但它應該是最後兩個DOWNLOAD_FILE調度等等isDownloading狀態之間的一些國家應該有正確的值。

+0

非常感謝Martin對你的幫助。我希望避免通過'DOWNLOAD_FILE_STARTED'創建另一個動作,因爲我想使用'DOWNLOAD_FILE' - 因爲現在該動作被reducer忽略,我想很好地使用它,這是不可能的? – Noitidart

+0

我想到另一種方式來做到這一點,我更新了我的答案,包括其他解決方案:) –

+0

非常酷,謝謝你馬丁!所以'watcher'總是在'worker'之前觸發的'reducer'之前觸發?這是生命週期嗎? – Noitidart