2017-10-12 45 views
0

我想弄清楚如何將同一個動作類型的多個任務取消在傳奇傳奇中。基本上,當我的組件在componentWillUnmount()時,我想取消它可能已經開始的所有任務。還原傳奇:取消同一動作類型/傳奇的多個任務

如果我有以下行爲(這是很大的,從我確實有我的代碼簡化,但我試圖削減下來的要領):

// Action 
export const loadMyData = params => { 
    let url = /* Create URL based on params */ 
    return { 
    type: FETCH_DATA, 
    url, 
    key: /* a unique key so we can retrieve it in the state later */ 
    } 
} 

而下面的傳奇:

// Saga 
export function* fetchData(action) { 
    try { 
    // 'callApi()' currently uses axios 
    let response = yield call(callApi, action.url); 

    yield put({ 
     type: FETCH_SUCCESS, 
     key: action.key, 
     payload: response.data 
    }); 
    } catch(error) { 
    yield put({ 
     type: FETCH_FAILURE, 
     error 
    }); 
    } 
} 

export function* watchFetchData() { 
    while (true) { 
    let action = yield take(FETCH_DATA); 
    let task = yield fork(fetchApi, action); 
    } 
} 

如上所述,組件可以多次調用loadMyData()。此外,還可能有其他組件,也稱爲loadMyData()。所以我試圖找到一種方法來取消只有處於componentWillUnmount()狀態的組件的任務,但保留其他正在運行的任務不變。

Redux Saga Cancellation documentation中,他們的示例適用於需要執行取消操作的單個任務。我無法弄清楚如何將其擴展到我的用例。

回答

1

什麼在我腦海的是以下幾點:

registerWatchFetchData = (componentKey) => { 
    return { 
    type: "REGISTER_WATCH_FETCH_DATA", 
    payload: { componentKey } 
    } 
} 

減速:

// ... 
case "REGISTER_WATCH_FETCH_DATA": 
    return {...state, tasks: {...state.tasks, [action.payload.componentKey]: []}} 

componentWillMount您通過調度動作,並在減速機存儲的任務,像這樣註冊您的組件

然後在function* watchFetchData()的內部,您將新任務存儲在reducer中,以便爲您提供的componentKey上的相應組件鍵值n個​​:

export function* watchFetchData() { 
    while (true) { 
    let action = yield take(FETCH_DATA); 
    let task = yield fork(fetchApi, action); 
    yield put({ type: "STORE_TASK", payload: { componentKey: action.payload.componentKey, task } }) 
    } 
} 

然後添加到減速器

// ... 
case "STORE_TASK": 
    return {...state, tasks: {...state.tasks, [action.payload.componentKey]: [...state.tasks[action.payload.componentKey], action.payload.task]}} 

而且在componentWillUnmount你發送另一個行動告訴一個傳奇拉開了componentKey所有任務,遍歷它們並取消他們都喜歡所以:

function* watchUnregisterComponent(){ 
    while(true){ 
     const action = yield take("UNREGISTER_WATCH_FETCH_DATA") 
     const componentTasks = yield select(state => state.myReducer.tasks[action.payload.componentKey]) 
     componentTasks.forEach((t) => { 
      yield cancel(t) 
     }) 
     // dispatch another action to delete them from the reducer 
    } 
}