Flux 动作在这个非常简单的虚拟应用程序上被错误的处理程序捕获,为啥?

Posted

技术标签:

【中文标题】Flux 动作在这个非常简单的虚拟应用程序上被错误的处理程序捕获,为啥?【英文标题】:Flux actions getting captured by wrong handlers on this very simple dummy app, Why?Flux 动作在这个非常简单的虚拟应用程序上被错误的处理程序捕获,为什么? 【发布时间】:2019-07-28 19:27:26 【问题描述】:

我有这个非常简单的React 应用程序:

https://codesandbox.io/s/24oq248v4n

大约是OrangesLemons,仅此而已。

它基本上从(模拟的)外部 API 获取 OrangesLemons,具体取决于按下的按钮。

下面是Oranges 商店的代码(Lemons 的代码非常相似)。

src\resources\assets\js\stores\OrangeStore.js

import  EventEmitter  from "events";
import  sprintf  from "sprintf-js";
import AppDispatcher from "../dispatcher/AppDispatcher";
import AppApi from "../utils/AppApi";

const CHANGE_EVENT = "change";
let _response = null;

class OrangeStore extends EventEmitter 
  constructor() 
    super();
    this.dispatchToken = AppDispatcher.register(this.handleActions.bind(this));
  

  emitChange() 
    this.emit(CHANGE_EVENT);
  

  addChangeListener(callback) 
    this.on(CHANGE_EVENT, callback);
  

  removeChangeListener(callback) 
    this.removeListener(CHANGE_EVENT, callback);
  

  fetchOranges(data) 
    AppApi.fetchOranges(data);
  

  setOrangeResponse(data) 
    _response = data;
  

  getOrangeResponse() 
    return _response;
  

  clearOrangeResponse() 
    _response = null;
  

  handleActions(action) 
    let nameObjectClass = this.constructor.name;
    switch (action.type) 
      case "FETCH_ORANGES":
        this.fetchOranges(action.value);
        break;
      case "SET_ORANGE_RESPONSE":
        this.setOrangeResponse(action.value);
        break;
      default:
        console.error(sprintf('ATTENTION: action: "%s" entered on the wrong handle, the one for: "%s".', action.type, nameObjectClass));
        break;
    
    this.emitChange();
  


export default new OrangeStore();

这里有负责调度操作的代码:

src\resources\assets\js\actions\AppActions.js

import AppDispatcher from "../dispatcher/AppDispatcher";

class AppActions 
  fetchOranges(data) 
    AppDispatcher.dispatch(
      type: "FETCH_ORANGES",
      value: data
    );
  
  setOrangeResponse(data) 
    AppDispatcher.dispatch(
      type: "SET_ORANGE_RESPONSE",
      value: data
    );
  
  fetchLemons(data) 
    AppDispatcher.dispatch(
      type: "FETCH_LEMONS",
      value: data
    );
  
  setLemonResponse(data) 
    AppDispatcher.dispatch(
      type: "SET_LEMON_RESPONSE",
      value: data
    );
  


export default new AppActions();

这里有主要代码:

src\index.js

import React from "react";
import ReactDOM from "react-dom";
import AppActions from "./resources/assets/js/actions/AppActions";
import OrangeStore from "./resources/assets/js/stores/OrangeStore";
import LemonStore from "./resources/assets/js/stores/LemonStore";

import "./styles.css";

class App extends React.Component 

  client = 
    firstName: 'George',
    lastName: 'Washington',
  ;

  componentWillMount() 
    OrangeStore.addChangeListener(this.handleOrangeResponse);
    LemonStore.addChangeListener(this.handleLemonResponse);
  
  componentWillUnmount() 
    OrangeStore.removeChangeListener(this.handleOrangeResponse);
    LemonStore.removeChangeListener(this.handleLemonResponse);
  

  getOranges = () => 
    AppActions.fetchOranges(this.client);
  ;
  getLemons = () => 
    AppActions.fetchLemons(this.client);
  ;

  handleOrangeResponse = () => 
    let response = OrangeStore.getOrangeResponse();
    console.log('inside: index.js / handleOrangeResponse() ... | where: response == ', response);
  
  handleLemonResponse = () => 
    let response = LemonStore.getLemonResponse();
    console.log('inside: index.js / handleLemonResponse() ... | where: response == ', response);
  

  render() 
    return (
      <div className="App">
        <h1>Oranges and Lemons</h1>
        <h2>Yet another Flux test!</h2>
        <button onClick=this.getOranges>Get Oranges</button>
        <button onClick=this.getLemons>Get Lemons</button>
      </div>
    );
  


const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

代码几乎可以正常工作,但是...

我的问题是:Oranges 对应的动作被Lemons 监听器捕获,反之亦然。

如下图所示:

邀请您亲自尝试:https://codesandbox.io/s/24oq248v4n

要查看结果:InfoErrors 您必须打开底部的 Code Sandbox 控制台。

在我看来,Oranges 的侦听器应该只捕获 Oranges 的操作,对于 Lemons 也是如此。

我相信我在这里省略了一个关键细节。

您对这种行为有任何想法吗?

如果可能,请在上面 fork 我的代码并在此处提供您的固定代码的链接。

也欢迎一些解释。

谢谢!

【问题讨论】:

【参考方案1】:

回答我自己的问题:

问题出在商店文件(两者)上,我有以下代码:

src\resources\assets\js\stores\OrangeStore.js(同样适用于其他商店)

class OrangeStore extends EventEmitter 

  ...

  handleActions(action) 
    let nameObjectClass = this.constructor.name;
    switch (action.type) 
      case "FETCH_ORANGES":
        this.fetchOranges(action.value);
        break;
      case "SET_ORANGE_RESPONSE":
        this.setOrangeResponse(action.value);
        break;
      default:
        console.error(sprintf('ATTENTION: action: "%s" entered on the wrong handle, the one for: "%s".', action.type, nameObjectClass));
        break;
    
    this.emitChange();
  

  ...


这里我犯了一个错误,它被我称为:this.emitChange(); 用于所有类型的操作,包括那些与相应商店无关的操作。

这是解决方案。

src\resources\assets\js\stores\OrangeStore.js(同样适用于其他商店)

class OrangeStore extends EventEmitter 

  ...

  handleActions(action) 
    switch (action.type) 
      case "FETCH_LEMONS":
        this.fetchLemons(action.value);
        // this.emitChange(); // THIS IS NOT NECESSARY HERE
        break;
      case "SET_LEMON_RESPONSE":
        this.setLemonResponse(action.value);
        this.emitChange();
        break;
    
  

  ...


还请注意,不必为每个操作调用:this.emitChange(),因为如果我们这样做,那么Flux 机制将调用不必要的事件处理程序(或回调),如果我们有某种对那些处理程序的预处理总是在执行其主要功能之前完成,然后我们将执行那些不必要的操作。

当我们与多家商店打交道时,如果我们没有考虑到这一点,我们就会遇到问题。

这里是固定的代码:https://codesandbox.io/s/0pml774y9l

在这里您可以快速预览主要更改:

这里很有趣:

https://scotch.io/tutorials/getting-to-know-flux-the-react-js-architecture

Dispatcher 基本上是整个流程的管理者。它是 您的应用程序的中心枢纽。调度程序接收动作 并将操作和数据分派给注册的回调。

所以它本质上是 pub/sub?

不完全是。调度程序将有效负载广播到其所有 注册的回调,并包括允许您 以特定顺序调用回调,甚至等待更新 在继续之前。只有一个调度程序,它充当 应用程序中的中心枢纽。

另外,这里有两个Flux 应用示例:

https://scotch.io/tutorials/build-a-react-flux-app-with-user-authentication

https://www.3pillarglobal.com/insights/getting-started-flux-react

注意他们打电话的地方:.emitChange()

谢谢!

【讨论】:

以上是关于Flux 动作在这个非常简单的虚拟应用程序上被错误的处理程序捕获,为啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Flux/React 中测试动作?

虚拟主机因隐私错误在 Chrome 上被阻止

如何为 RelayMutations 触发 Flux 动作

商店的变更监听器没有在 componentWillUnmount 上被删除?

关于redux应用

没有动作和调度程序的通量?