2017-05-26 5 views
0

接続されたコンテナでは、エラーを捕捉して処理するために、より高次のレデューサー(以下を参照)でラップされたレデューサーがあります。 componentDidMountの間にフェッチ要求を呼び出すと失敗すると、接続されているコンテナ自体がアンマウントされますcomponentWillUnmount。これにより、コンテナ内に無限ループが発生し、再度マウントされ、フェッチが失敗し、コンテナ自体がアンマウントされます。フェッチで無限のコンポーネントライフサイクルループが発生する

接続コンポーネントで高次減速器を使用する理由は何ですか?

エラー処理上位リデューサ:

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()が放されているときはいつでも、親はそのイベントをキャッチし、子(ここではPageを含む)を再レンダリングします。グローバルな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

関連する問題