takeEvery但它丢弃每一个

时间:2017-08-06 23:07:09

标签: redux-saga

我试图一次只处理一个给定ID的下载。我想要它非阻塞,所以"不同的文件ID"可以并行下载,这就是为什么我在做takeEvery。我想丢弃一个"相同的文件ID"已经在进行中。

一旦调度了动作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 个答案:

答案 0 :(得分:1)

这是因为当调度action时,reducer总是先执行,然后才执行saga。解决此问题的一种方法是将流分为两个动作。 One - DOWNLOAD_FILE - 启动传奇然后再启动 -  例如DOWNLOAD_FILE_STARTED - 当isDownloading为false并从更新isDownloading状态时从saga调度:

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状态应该具有正确的值。