2016-11-10 8 views
0

のために呼び出されてReduxのミドルウェアで、私は、私は同様の非同期呼び出しを呼び出すために使用し、次のミドルウェアがありますPromise.catch無関係減速

import { callApi } from '../utils/Api'; 

import generateUUID from '../utils/UUID'; 

import { assign } from 'lodash'; 

export const CALL_API = Symbol('Call API'); 

export default store => next => action => { 
    const callAsync = action[CALL_API]; 

    if(typeof callAsync === 'undefined') { 
    return next(action); 
    } 

    const { endpoint, types, data, authentication, method, authenticated } = callAsync; 

    if (!types.REQUEST || !types.SUCCESS || !types.FAILURE) { 
    throw new Error('types must be an object with REQUEST, SUCCESS and FAILURE'); 
    } 

    function actionWith(data) { 
    const finalAction = assign({}, action, data); 
    delete finalAction[CALL_API]; 

    return finalAction; 
    } 

    next(actionWith({ type: types.REQUEST })); 

    return callApi(endpoint, method, data, authenticated).then(response => { 
    return next(actionWith({ 
     type: types.SUCCESS, 
     payload: { 
     response 
     } 
    })) 
    }).catch(error => { 
    return next(actionWith({ 
     type: types.FAILURE, 
     error: true, 
     payload: { 
     error: error, 
     id: generateUUID() 
     } 
    })) 
    }); 
}; 

を私は、コンポーネントのcomponentWillMountで、次の呼び出しを作っていますミドルウェアによって処理されたアクションを派遣する例えば

componentWillMount() { 
    this.props.fetchResults(); 
    this.props.fetchTeams(); 
    } 

fetchTeamsは、それは次のようになります。

export function fetchTeams() { 
    return (dispatch, getState) => { 
    return dispatch({ 
     type: 'CALL_API', 
     [CALL_API]: { 
     types: TEAMS, 
     endpoint: '/admin/teams', 
     method: 'GET', 
     authenticated: true 
     } 
    }); 
    }; 
} 

成功のアクションが両方ともディスパッチされ、新しい状態がレデューサーから返されます。両方の減速は、同じように見えると以下Teams減速される:

render() { 
    <div> 
    <Autocomplete items={teams}/> 
    </div> 
} 

オートコンプリートはそのcomponentWillMountでアクションをディスパッチ:

class Autocomplete extends Component{ 
    componentWillMount() { 
    this.props.dispatch(actions.init({ props: this.exportProps() })); 
    } 

export const initialState = Map({ 
    isFetching: false, 
    teams: List() 
}); 

export default createReducer(initialState, { 
    [ActionTypes.TEAMS.REQUEST]: (state, action) => { 
    return state.merge({isFetching: true}); 
    }, 

    [ActionTypes.TEAMS.SUCCESS]: (state, action) => { 
    return state.merge({ 
     isFetching: false, 
     teams: action.payload.response 
    }); 
    }, 

    [ActionTypes.TEAMS.FAILURE]: (state, action) => { 
    return state.merge({isFetching: false}); 
    } 
}); 

成分は、その後、別のアクションをディスパッチする別のコンポーネントを描画します

SUCCESSレデューサーがのために呼び出された後に呼び出されるオートコンプリートレデューサーでエラーが発生します。とfetchResults親コンポーネントのcomponentWillUpdateの元呼び出しからではなく最初のコードスニペットからミドルウェアでのcatchハンドラが呼び出され、何らかの理由:catchハンドラとして呼び出されている理由

return callApi(endpoint, method, data, authenticated).then(response => { 
    return next(actionWith({ 
     type: types.SUCCESS, 
     payload: { 
     response 
     } 
    })) 
    }).catch(error => { 
    return next(actionWith({ 
     type: types.FAILURE, 
     error: true, 
     payload: { 
     error: error, 
     id: generateUUID() 
     } 
    })) 
    }); 
}; 

私は理解していません私はこの時点で約束が解決されたと思ったでしょう。

答えて

1

完全にはわかりませんが、コードを読むことでデバッグするのは難しいです。明らかなのは、next(actionWith({ type: types.SUCCESS, payload: { response } }))の呼び出しの同じスタックトレース内ですべてが起きているからです。この場合はそう

  1. ミドルウェア:発送はReduxの更新が
  2. 小道具Promise.then
  3. 内部成功が反応:新しい小道具
  4. をレンダリングが反応:componentWillMount
  5. が反応:派遣新しいアクションを

エラーが発生した場合は、Promise.thenまでバブルアップし、Promise.catchコールバックを実行します。

setTimeoutの中でオートコンプリートフェッチを呼び出して、現在のスタックトレースが終了し、次の「イベントループ」でフェッチを実行できるようにしてください。

setTimeout(
() => this.props.dispatch(actions.init({ props: this.exportProps() })) 
); 

これが動作する場合、エラーが発生し、すべての方法レンダリングオートコンプリートへのミドルウェア成功派遣から関数は関数呼び出しの後に呼び出されますされているときにイベントループの処理が終了していないと、その事実。

:あなたは多分あなたはあなたのAPIリクエストの非同期を作成する方法についてのライブラリからいくつかのインスピレーションを得ることができますカスタムミドルウェアを使用しておきたい場合は、非同期タスクのためのReduxのループ、またはReduxの-佐賀の使用を検討すべきです最初の発送から。

+0

本当に正しいです。私は次のチックでアクションをディスパッチするときに正しいスタックトレースを取得します。 ループには、使用しているキューがいくつかあると思います。私はそれを掘り下げるつもりです。ご協力ありがとうございました。 – dagda1