简体   繁体   中英

React, React Router and Flux: “dispatch in the middle of a dispatch” when I try to clear the messages on store

I'm using React, React Router and Flux.

I have a MessageStore that holds the messages (error, warning or success) that the components of my application trigger using MessagesAction.addError() , MessagesAction.addWarning() and MessagesAction.addSucess() .

The message is dispatched and the MessageStore is registered on the Dispatcher to receive the message and store the message.

After that, the store emit an event to call the callback methods listening for new messages. Nothing new until here.

My problem is: I need to clear the messages on the MessageStore when the path (URL) is changed.

My first try is listen the route changes and dispatch an action to clear the messages. The code:

generic-component.jsx

onClickButton: updateGenericInformation() {
    GenericAction.updateInformation(this.state.information);
},

componentDidMount: function() {
    //listening for the update in GenericStore.
    GenericStore.addChangeListener(this.changeRoute);
}

changeRoute: function () {
    this.history.pushState(null, '/my-page');
},

routes.jsx

clearMessages: function() {
    MessagesAction.clear();
},

ReactDOM.render(<Router onUpdate={this.clearMessages}>{routes}</Router>, appElement);

MessagesAction

clear: function() {
    Dispatcher.dispatch({ // error happen here...
        actionType: 'CLEAR'
    });
}

MessagesStore

case 'CLEAR':
    _messages = [];
    EventEmitter.prototype.emit('EVENT_MESSAGES_UPDATED');
    break;

The error:

flux.js:41 Uncaught Error: Invariant Violation: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.

Actually, to clear the messages, each component calls the clear action from MessagesAction in his own DidMount method, what is not a good solution.

I tried too to clear the messages in my messages component in the update cycle of the component (after I receive the message and save in the state):

messages.jsx

componentDidUpdate function() {
    if (this.state.messages) {
         MessagesAction.clear();
    }
}

I receive the same error.

So, what is the good practice in React and Flux to do this? I would like to not use setTimeout in the solution.

I've had success with something like this, I just put this in my routes file.

browserHistory.listen(location => {
    // fire your action here to clear the state you need
});

I'm not sure the same mechanism is in place, but when I've tried to add change handlers on the route itself, proper, I'd have more issues than I wanted.

Fix rule here. You can't emit another event inside the store, store should be purely synchronous. so this line is the issue. "EventEmitter.prototype.emit('EVENT_MESSAGES_UPDATED');"

So I'm guessing you're trying to achieve something like this

  1. componentDidMount/Update()

  2. Shout "Clear! (CLEAR)" to Mr. A (Message Store)

  3. Message has been cleared

  4. Let Mr.A shout again to Mr. B (Some other store) "It has been cleared! (EVENT_MESSAGES_UPDATED)"

(Note: Shout is equal to dispatching thing)

You could reduce flow to.

  1. componentDidMount/Update()

  2. Shout "Clear! (CLEAR)"

  3. Have Mr.A (MessageStore) and Mr.B (SomeOtherStore) both listen to 'CLEAR' and do stuff respectively.

so your MessageStore will be

case 'CLEAR':
    _messages = [];
    break;

And your Mr. B (some other store that originally listened to 'EVENT_MESSAGES_UPDATED', let it listen to 'CLEAR' instead

// case 'EVENT_MESSAGES_UPDATED'
case 'CLEAR':
    // Do something you intend to do after EVENT_MESSAGES_UPDATED
    break;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM