2017-07-15 49 views
3

我有一個redux-observables的問題。在我的情況下,史詩般的等待結束另一部史詩。第二部史詩可以從緩存發出請求或返回數據。 當第二個請求全部按預期工作時,但當它返回緩存時,第一個不會繼續。史詩不會對來自另一史詩的行動作出反應

const { Observable } = Rx; 

const FETCH_USER = 'FETCH_USER'; 
const FETCH_USER_FULFILLED = 'FETCH_USER_FULFILLED'; 
const FETCH_USER2 = 'FETCH_USER2'; 
const FETCH_USER_FULFILLED2 = 'FETCH_USER_FULFILLED2'; 
const FETCH_USER_REJECTED = 'FETCH_USER_REJECTED'; 
const FETCH_USER_CANCELLED = 'FETCH_USER_CANCELLED'; 

const fetchUser = id => ({ type: FETCH_USER, payload: id }); 
const fetchUserFulfilled = payload => ({ type: FETCH_USER_FULFILLED, payload }); 
const fetchUser2 = id => ({ type: FETCH_USER2, payload: id }); 
const fetchUserFulfilled2 = payload => ({ type: FETCH_USER_FULFILLED2, payload }); 
const cancelFetchUser =() => ({ type: FETCH_USER_CANCELLED }); 

let isFetchced = false; 

const fakeAjax = url => 
    Observable.of({ 
    id: url.substring(url.lastIndexOf('/') + 1), 
    firstName: 'Bilbo', 
    lastName: 'Baggins' 
    }).delay(1000); 

const fakeAjax2 = url => 
    Observable.of({ 
    id: url.substring(url.lastIndexOf('/2') + 1), 
    firstName: 'Bilbo2', 
    lastName: 'Baggins2' 
    }).delay(1000); 

const fetchUserEpic = (action$, store) => 
    action$.ofType(FETCH_USER) 
    .mergeMap(action => { 
     const observable = isFetchced ? Observable.of({ 
     id: 2, 
     firstName: 'Bilbo', 
     lastName: 'Baggins' 
     }) : fakeAjax(`/api/users/${action.payload}`); 
     isFetchced = true; 
     console.log(action); 
     return observable 
     .map(response => fetchUserFulfilled(response)) 
     .takeUntil(action$.ofType(FETCH_USER_CANCELLED)) 
    }); 

const fetchUserEpic2 = action$ => 
    action$.ofType(FETCH_USER2) 
    .switchMap(() => action$.ofType(FETCH_USER_FULFILLED) 
       .take(1) 
    .mergeMap(() => { 
     console.log("First epic"); 
     return fakeAjax2(`/api/users/${1}`) 
      .map(response => fetchUserFulfilled2(response)) 
    }).startWith(fetchUser('redux-observable'))); 

const users = (state = {}, action) => { 
    switch (action.type) { 
    case FETCH_USER_FULFILLED: 
     return { 
     ...state, 
     [action.payload.id]: action.payload 
     }; 

    default: 
     return state; 
    } 
}; 

const isFetchingUser = (state = false, action) => { 
    switch (action.type) { 
    case FETCH_USER: 
     return true; 

    case FETCH_USER_FULFILLED: 
    case FETCH_USER_CANCELLED: 
     return false; 

    default: 
     return state; 
    } 
}; 

這裏是仿真https://jsbin.com/qitutixuqu/1/edit?html,css,js,console,output。在控制檯上點擊「獲取用戶信息」按鈕後,您可以看到「第一個史詩」,在第二次點擊按鈕後,控制檯中沒有消息。如果將延遲添加到

Observable.of({ 
    id: 2, 
    firstName: 'Bilbo', 
    lastName: 'Baggins' 
}).delay(10) 

它開始按預期工作。

+0

FYI我想幫助,但無法弄清楚的期望是什麼,問題是什麼。移動部件過多。 jsbin也與所提供的示例不同,這增加了混淆。 – jayphelps

回答

3

簡答:在fetchUserEpic中,第一次點擊是異步的,返回1000 ms的延遲。第二次點擊是fetchUserEpic的完全同步執行,導致內部actions$.ofType(FETCH_USER_FULFILLED)錯過fetchUserEpic2中的操作。

說明:

跟蹤fetchUserEpic在第一次點擊,我們得到這樣的:

fetchUserEpic src: FETCH_USER2 
fetchUserEpic2 src: FETCH_USER2 
fetchUserEpic2 in: FETCH_USER2 
fetchUserEpic2 out: FETCH_USER 
fetchUserEpic src: FETCH_USER 
fetchUserEpic in: FETCH_USER 
fetchUserEpic2 src: FETCH_USER <- Notice location 
fetchUserEpic out: FETCH_USER_FULFILLED 
fetchUserEpic src: FETCH_USER_FULFILLED 
fetchUserEpic2 src: FETCH_USER_FULFILLED 
fetchUserEpic2-inner src: FETCH_USER_FULFILLED <- now subscribed 
fetchUserEpic2-inner in: FETCH_USER_FULFILLED 
First epic 
fetchUserEpic2 out: FETCH_USER_FULFILLED2 
fetchUserEpic src: FETCH_USER_FULFILLED2 
fetchUserEpic2 src: FETCH_USER_FULFILLED2 

跟蹤第二次我們得到:

fetchUserEpic src: FETCH_USER2 
fetchUserEpic2 src: FETCH_USER2 
fetchUserEpic2 in: FETCH_USER2 
fetchUserEpic2 out: FETCH_USER 
fetchUserEpic src: FETCH_USER 
fetchUserEpic in: FETCH_USER 
fetchUserEpic out: FETCH_USER_FULFILLED 
fetchUserEpic src: FETCH_USER_FULFILLED 
fetchUserEpic2 src: FETCH_USER_FULFILLED 
fetchUserEpic2 src: FETCH_USER <- Notice location 

由於fetchUserEpic2訂購了到actions$在switchMap聲明,它不會收到已分派的操作。 redux-observable使用常規的Subject,而不是ReplaySubject或類似的,因此如果在預訂之前調度該操作,那麼操作$ subscription將會錯過操作。出於這個原因,您需要謹慎行事,以確保在您取決於fetchUserEpic2正在使用的內部訂閱時異步地分派操作。

下面是修改後的源與跟蹤記錄語句:

const fetchUserEpic = (action$, store) => 
    action$ 
    .do(a => console.log(`fetchUserEpic src: ${a.type}`)) 
    .ofType(FETCH_USER) 
    .do(a => console.log(`fetchUserEpic in: ${a.type}`)) 
    .mergeMap(action => { 
     const observable = isFetchced ? Observable.of({ 
     id: 2, 
     firstName: 'Bilbo', 
     lastName: 'Baggins' 
     }) : fakeAjax(`/api/users/${action.payload}`); 
     return observable 
     .map(response => (isFetchced = true,fetchUserFulfilled(response))) 
     .takeUntil(action$.ofType(FETCH_USER_CANCELLED)) 
    }) 
    .do(a => console.log(`fetchUserEpic out: ${a.type}`)); 

const fetchUserEpic2 = action$ => 
    action$ 
    .do(a => console.log(`fetchUserEpic2 src: ${a.type}`)) 
    .ofType(FETCH_USER2) 
    .do(a => console.log(`fetchUserEpic2 in: ${a.type}`)) 
    .switchMap(() => 
     action$ 
     .do(a => console.log(`fetchUserEpic2-inner src: ${a.type}`)) 
     .ofType(FETCH_USER_FULFILLED) 
     .do(a => console.log(`fetchUserEpic2-inner in: ${a.type}`)) 
     .take(1) 
     .do(() => console.log("First epic")) 
     .mergeMap(() => 
      fakeAjax2(`/api/users/${1}`) 
      .map(response => fetchUserFulfilled2(response)) 
     ).startWith(fetchUser('redux-observable'))) 
    .do(a => console.log(`fetchUserEpic2 out: ${a.type}`)); 
相關問題