javascript - 在这个非常简单的虚拟应用程序上,错误的处理程序捕获了通量动作,为什么?
问题描述
我有这个非常简单的React
应用程序:
https://codesandbox.io/s/24oq248v4n
大约是Oranges
和Lemons
,仅此而已。
它基本上从(模拟的)外部 API 获取Oranges
or Lemons
,具体取决于按下的按钮。
下面是商店的代码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
要查看结果:Info
您Errors
必须打开Code Sandbox
底部的控制台。
在我看来,监听器Oranges
应该只捕获Oranges
动作,对于:Lemons
。
我相信我在这里省略了一个关键细节。
您对这种行为有任何想法吗?
如果可能,请在上面分叉我的代码并在此处提供您的固定代码的链接。
也欢迎一些解释。
谢谢!
解决方案
回答我自己的问题:
问题出在商店文件(两者)上,我有以下代码:
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 基本上是整个流程的管理者。它是您的应用程序的中心枢纽。分派器接收动作并将动作和数据分派给注册的回调。
所以它本质上是发布/订阅?
不完全是。调度程序将有效负载广播到其所有已注册的回调,并包含允许您以特定顺序调用回调的功能,甚至在继续之前等待更新。只有一个调度程序,它充当应用程序中的中心枢纽。
此外,这里有两个Flux
应用程序示例:
https://scotch.io/tutorials/build-a-react-flux-app-with-user-authentication
https://www.3pillarglobal.com/insights/getting-started-flux-react
注意他们打电话的地方:.emitChange()
。
谢谢!
推荐阅读
- javascript - 当应用程序在后台时Websocket断开连接
- java - 使用 Jackson 将名称值对数组反序列化为对象
- regex - 获取端口而不从正则表达式获取 ip
- google-cloud-vision - 当我们在 Google-AutoMl 中再次恢复经过训练的模型时,定价模型将是什么
- python - 如何返回根据其子列表组件排列的列表
- vue.js - store/ 的 Vuex Classic 模式已弃用,将在 Nuxt 3 中删除
- google-apps-script - googlesparesheets 参数传递问题
- android - 错误 CS0103:当前上下文中不存在名称“资源”
- python - 如果数据在 numpy 数组中,保存 numpy 记录文件会占用更多空间,如果数据在列表中则更少
- c# - 具有共享资源的观察者模式中的 C# 竞争条件预防