reactjs - Promise.catch in redux middleware being invoked for unrelated reducer -


i have following middleware use call similar async calls:

import { callapi } '../utils/api';  import generateuuid '../utils/uuid';  import { assign } '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 object request, success , 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()       }     }))   }); }; 

i making following calls in componentwillmount of component:

  componentwillmount() {     this.props.fetchresults();     this.props.fetchteams();   } 

fetchteams example dispatch action handled middleware, looks this:

export function fetchteams() {   return (dispatch, getstate) => {     return dispatch({       type: 'call_api',       [call_api]: {         types: teams,         endpoint: '/admin/teams',         method: 'get',         authenticated: true       }     });   }; } 

both success actions dispatched , new state returned reducer. both reducers same , below teams reducer:

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});   } }); 

the component renders component dispatches action:

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

autocomplete dispatches action in componentwillmount:

class autocomplete extends component{   componentwillmount() {     this.props.dispatch(actions.init({ props: this.exportprops() }));   } 

an error happens in autocomplete reducer invoked after success reducers have been invoked fetchteams , fetchresults original calls in componentwillupdate of parent component reason catch handler in middleware first code snippet invoked:

  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()       }     }))   }); }; 

i not understand why catch handler being invoked have thought promise has resolved @ point.

am not sure, it's hard debug reading code. obvious answer because it's happening within same stacktrace of call next(actionwith({ type: types.success, payload: { response } })).

so in case:

  1. middleware: dispatch fetchteam success inside promise.then
  2. redux update props
  3. react: render new props
  4. react: componentwillmount
  5. react: dispatch new action

if error occurs @ point, bubble promise.then, makes execute promise.catch callback.

try calling autocomplete fetch inside settimeout let current stacktrace finish , run fetch in next "event loop".

settimeout(   () => this.props.dispatch(actions.init({ props: this.exportprops() })) ); 

if works, its' fact event loop hasn't finished processing when error occurs , middleware success dispatch way autocomplete rendered function calls after function calls.

note: should consider using redux-loop, or redux-saga asynchronous tasks, if want keep using custom middleware maybe can inspiration libraries on how make api request async initial dispatch.


Comments

Popular posts from this blog

aws api gateway - SerializationException in posting new Records via Dynamodb Proxy Service in API -

asp.net - Problems sending emails from forum -