2017-05-26 26 views
0

對於連接的容器,我有一個reducer,它被更高階的reducer(如下所示)包裹以捕獲和處理錯誤。當在componentDidMount期間調用提取請求並且失敗時,連接的容器將自行卸載componentWillUnmount。這將導致容器中的無限循環,因爲它將再次裝入,取出將失敗,並且容器將自行卸載。失敗的提取導致無限的組件生命週期循環

任何想法爲什麼在連接組件中具有更高階的reducer造成這種情況?

錯誤處理高階減速器:

export const errorHandler = (reducer: (state: any, action: { type: string }, initialState: any) => {}) => { 
    const errorState = fromJS({ 
     error: { 
      hasError: false, 
      message: "", 
     }, 
    }); 

    const initialState = errorState.merge(reducer(undefined, { type: undefined }, undefined)); 

    return (state = initialState, action) => { 
     switch (action.type) { 
      case ACTIONS.SET_ERROR: 
       return state.setIn(["error", "hasError"], true) 
        .setIn(["error", "message"], action.message); 

      case ACTIONS.CLEAR_ERROR: 
       return state.set("error", errorState.get("error")); 

      default: 
       return reducer(state, action, initialState); 
     } 
    }; 
}; 

實施例容器:

class Page extends Component { 
    componentDidMount() { 
     this.props.fetch(....); 
    } 
    componentWillUnmount() { 
     this.props.clearData(); 
     this.props.cancelRequests(); 
    } 
} 

export default connect(
    (state) => ({ 
     error: state.data.get("error", ""), 
    }), 
    { 
     clearError, 
     clearData, 
     cancelRequests, 
    }, 
)(Page); 

實施例減速機:

export fetch =() => ({ 
    type: ACTIONS.FETCH 
}); 

export default errorHandler((state, action) => { 
    switch(action.type) { 
    default: 
     return state; 
    } 
})); 

史詩:

export const fetch = (action$: any, store: any, api: API) => { 
    return action$.ofType(ACTIONS.FETCH) 
     .mergeMap((action: any) => 
      fromPromise(api.fetch(action.data)) 
       .pluck("Data") 
       .map(data) => 
        fetchFulfilled(data), 
       ) 
       .catch((response) => { 
        const toPromise = typeof response.json === "function" ? response.json() : new Promise((resolve) => resolve(response)); 

        return fromPromise(toPromise) 
         .pluck("Message") 
         .map((Message: string) => 
          setError(Message)); 
       }) 
       .takeUntil(action$.ofType(ACTIONS.CANCEL_REQUESTS))); 
}; 
+1

通常組件卸載,因爲他們的父母不再使他們的任何情況組件可以卸載本身(不包括黑客)。 的父項是什麼樣的? (我實際上沒有意識到組件可以卸載自身的任何情況,但也許有可能) – jayphelps

+0

這正是問題所在。在深入研究這個問題之後,我發現了一個使用相同的errorHandler()高階簡化器的父組件。每當setError()被解僱時,父母都會捕獲該事件,並重新展示其子項(包括頁面在內)。切換使用全局setError()動作完全解決了這個問題。 – dpaulus

回答

1

基於我們在評論中的對話:

通常組件卸載,因爲他們的父母不再使他們。父母的樣子是什麼?您可能會在哪裏查找您的組件未安裝的原因。

我不知道的

0

我認爲你只需要捕獲錯誤,而不是讓異常被React掛載代碼捕獲。

try { 
    this.props.fetch(....); 
} 
catch (e) { 
    //Do whatever is appropriate to handle the fetch failure. Maybe you want... 
    this.setState({ error: {hasError: true, message: '' + e}); 
} 

我認爲的setState()調用上面是不是適合你的預期減速機實現,但是這是可以解決(或詢問更多的問題),一個單獨的問題。您的問題的主要部分似乎是停止卸載/重新安裝行爲。

+0

感謝您的幫助! 我忘記提及我使用Redux-Observable,所以在這種情況下'this.props.fetch()'只是調度一個操作 - 而不是執行請求。不幸的是,將它封裝在try/catch中是行不通的。 原始帖子中的示例已更新。 – dpaulus