Flux/Alt Basic async example throws "Cannot dispatch in the middle of a dispatch"

I'm struggling to get around the Cannot dispatch in the middle of a dispatch error Flux is throwing at me, with a basic example.

On my view, I've got a button which triggers a socialLogin(token) action, on my AuthActions. With Alt on my Action, I generateActions('login');

My socialLogin method performs an Async API request which returns a promise (Api is a simple class using a request lib):

// AuthActions
socialLogin(type, access_token) {
    Api.request('get', 'auth/social', { type, access_token })
       .then((payload) => {
           if (payload.code !== 'OK') {
               // Do something...
           } else {
               this.actions.login(payload.data.token);
           }
       })
       .catch((response) => {
           console.log('ERROR', response);
           // Do something....
       });
    this.dispatch();
}

The Store onLogin method currently does nothing.

However running this throws/catches the error Uncaught (in promise) Error: Invariant Violation: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.(…).

I cannot understand why, after reading many issues/articles - shouldn't the this.dispatch() "resolve" the current action being dispatched?

How would I go about triggering some other action here, or even trigger multiple actions (login, use another external action etc).

Thanks!

Answers


I think in your example you can just omit the this.dispatch(); line entirely, and it should. The action creator function socialLogin is called as part of a dispatch itself, so it is not allowed to call dispatch. If you do want to dispatch a socialLogin action at the start of the login process (e.g. to allow putting up a spinner or something), you could return the payload you want to dispatch. e.g. replace this.dispatch(); with

return { type, access_token }; 

That way stores can listen to socialLogin if they want to catch the start of the process.


what you need is this.actions.myAnotherAction(), where myAnotherAction is another action within the AuthActions in your case. Look


inside the action, just return a promise like:

 socialLogin(type, access_token) {
  return (dispatch) => {
    dispatch({type:type, accessToken:access_token});
    return new Promise((resolve,reject)=>{
      Api.request('get', 'auth/social', { type, access_token })
      .then((payload) => {
       if (payload.code !== 'OK') {
           // Do something...
       } else {
           this.actions.login(payload.data.token);
       }
       resolve(payload);
       })
       .catch((response) => {
       console.log('ERROR', response);
       // Do something....
       reject(response);
       });
    }
  }

}

Also sometimes in the container/controller views, you might be calling actions as a result of this action which will lead to the same error. In that just call any subsequent acction with defer option in dispatch like:

  myaction.actionname.defer(options);

Need Your Help

error: linker command failed with exit code 1 (use -v to see invocation) " -ObjC "

ios iphone xcode admob

I have a problem add ads Admob when I try adding ads at the last step when the trial shows the error >>>>>

Expressjs Mongoose find nested embedded documents are undefined

javascript node.js mongodb express mongoose

I'm building a game with nodejs 0.6.18 expressjs 2.5.8 and mongoose 2.6.7.