【问题标题】:React, React Router and Flux: “dispatch in the middle of a dispatch” when I try to clear the messages on storeReact、React Router 和 Flux:当我尝试清除存储中的消息时,“在调度过程中调度”
【发布时间】:2017-02-16 21:11:10
【问题描述】:

我正在使用 React、React Router 和 Flux。

我有一个MessageStore,其中包含我的应用程序组件使用MessagesAction.addError()MessagesAction.addWarning()MessagesAction.addSucess() 触发的消息(错误、警告或成功)。

消息被分派,MessageStore 在 Dispatcher 上注册以接收消息并存储消息。

之后,store 会发出一个事件来调用回调方法来监听新消息。在此之前没有什么新鲜事。

我的问题是:当路径(URL)改变时,我需要清除MessageStore上的消息。

我的第一个尝试是监听路由变化并发送一个动作来清除消息。代码:

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;

错误:

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

实际上,为了清除消息,每个组件在自己的DidMount方法中从MessagesAction调用清除动作,这不是一个好的解决方案。

我也尝试在组件的更新周期中清除我的消息组件中的消息(在我收到消息并保存状态后):

messages.jsx

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

我收到同样的错误。

那么,在 React 和 Flux 中有什么好的做法来做到这一点?我不想在解决方案中使用setTimeout

【问题讨论】:

  • 为什么你需要使用一些商店来监听路由变化? onUpdate 处理程序会在 React Router 检测到路由更改时触发。
  • 当您尝试执行 dispatch CLEAR 操作时会发生什么样的错误?
  • @KonstantinGrushetsky,嗨!感谢您的关注。当路由发生变化时,我需要清除 MessagesStore。我没有使用特定的商店(如“PathStore”)来保存路径并收听来自该商店的更改。我也添加了错误。
  • 是的,问题是您无法从存储中分派事件(像这样) - 分派器等待所有回调完成并且您正在同步分派这个新事件。这是您设计的问题;但是,解决它的一种方法是进行 ajax 调用(例如),该调用将是异步的(您可以在其回调中发出),或者做您不想做的事情(hacky) - 超时,再次是异步的,例如。类似var self = this; setTimeout(function() { self.emit('EVENT_MESSAGES_UPDATED'); }, 0);
  • @elektronik 嗨! setTimeout“是一种黑客行为,应该避免”(github.com/facebook/flux/issues/138#issuecomment-88969327)。

标签: reactjs react-router flux


【解决方案1】:

我在这样的事情上取得了成功,我只是把它放在我的路线文件中。

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

我不确定是否有相同的机制,但是当我尝试在路由本身上添加更改处理程序时,我会遇到比我想要的更多的问题。

【讨论】:

    【解决方案2】:

    在此处修复规则。您不能在商店内发出另一个事件,商店应该是纯同步的。所以这条线是问题所在。 "EventEmitter.prototype.emit('EVENT_MESSAGES_UPDATED');"

    所以我猜你正在尝试实现这样的目标

    1. componentDidMount/Update()

    2. 向 A 先生(消息存储)喊“清除!(清除)”

    3. 消息已被清除

    4. 让 Mr.A 再次对 Mr.B(其他一些商店)喊“它已被清除!(EVENT_MESSAGES_UPDATED)”

    (注:喊就等于派东西)

    您可以减少流量。

    1. componentDidMount/Update()

    2. 喊“清除!(清除)”

    3. 让 Mr.A (MessageStore) 和 Mr.B (SomeOtherStore) 分别收听“CLEAR”并执行操作。

    所以你的 MessageStore 将是

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

    还有你的B先生(原来听'EVENT_MESSAGES_UPDATED'的其他商店,让它听'CLEAR'代替

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

    【讨论】:

    • 嗨!我的问题是,当 URL 更改时,我仍然使用 GenericAction 进行调度,并使用我的 routes.jsx 中的 MessagesAction 进行另一次调度。 Generic 商店(和其他商店)不需要知道清除消息的操作。
    猜你喜欢
    • 2016-01-29
    • 2016-06-23
    • 2016-04-22
    • 1970-01-01
    • 1970-01-01
    • 2016-03-03
    • 2015-06-29
    • 2016-12-03
    • 2014-12-22
    相关资源
    最近更新 更多