我有一串 Rx.Subjects (A->B->C->A),但最后一步不起作用
I have a chain of Rx.Subjects (A->B->C->A), but the final step is not working
我对 Rx* 完全陌生。我正在尝试为我的论文使用 RxJS 创建 MVC 的反应版本。它大致基于 https://github.com/staltz/mvi-example
我可能应该在开始编码之前更多地研究 RxJS,但我意识到我通常只是跳到游泳池的深处才能学到最好的东西。但是现在我完全卡住了。
视图有一个带有数值的文本字段和一个按钮。按下按钮会更改文本的颜色,单击文本会迭代数值。该值存储在模型中,因此 "chain" 遍历所有三个对象(View->Controller->Model->View)。按下按钮不需要模型,所以链是View->Controller->View。
其他一切正常,但链的最后部分 (->View) 给我带来了麻烦。单击文本(在视图中)会将更改传播到控制器和模型,但不会通知视图模型中的更改。我不明白为什么,因为我理解的方式所有这些都是以相同的方式实现的。
我在下面的代码示例中添加了注释以指定不被调用的函数。
代码可用 here。请注意,就像我说的那样,代码是为了我的论文,所以一些设计决策和应用程序本身可能看起来很奇怪。下面我还尝试包括我认为最相关的部分。我知道我应该提供一个完整的例子,但在这种情况下这是不可能的。
objects获取的"obs"参数是我用来存储observables的内部数据结构。相关部分是
var OBSERVABLES = {
observe: function(source, observer, observer_name) {
this.request(source, function(s) {
console.log("\t[" + source + " is being observed by " + observer_name + " (" + s.constructor.name + " -> " + observer.constructor.name + ")]")
return s.subscribe(
function myOnNext(x) {
console.log("\t(" + source + ") " + s.constructor.name + " -> OnNext -> (" + observer_name + ") " + observer.constructor.name)
observer.onNext(x)
},
function myOnError(err) {
console.log(error)
})
})
},
View.js
var modelAmount = new Rx.Subject()
var textClicks = new Rx.Subject()
var buttonClicks = new Rx.Subject()
var changeColors = new Rx.Subject()
function View(obs, div) {
console.log("View :: New View")
obs = obs
div = div
var self = this
obs.observe("clickAmount", modelAmount, "modelAmount")
obs.observe("changeColor", changeColors, "changeColors")
obs.add("textClicks", textClicks)
obs.add("buttonClicks", buttonClicks)
//Draw HTML elements
render(div);
}
...
function onClick() {
console.log("View :: onClick() emits 'textClicks'");
textClicks.onNext()
}
function onButtonClick() {
console.log("View :: onButtonClick() emits 'buttonClicks'");
buttonClicks.onNext()
}
//Listen to controllers instruction to change the color
// DOES NOT WORK
var changeNumberColor = changeColors.map(function(c) {
console.log("View :: Listened to 'changeColor'")
if (c === undefined) {
c = getColor()
}
CONTENT.css('color', c)
});
//Listen to model's instruction to change the value
// DOES NOT WORK
var setValue = modelAmount.last(function(latestValue) {
console.log("View :: Listened to 'clickAmount'")
console.log("View :: setValue(" + latestValue + ")")
CONTENT.text(latestValue)
});
Controller.js
var inputTextClicks = new Rx.Subject();
var inputButtonClicks = new Rx.Subject();
var obs = null;
function Controller(obs){
console.log("Controller :: New Controller")
obs = obs
obs.observe("textClicks", inputTextClicks, "inputTextClicks")
obs.observe("buttonClicks", inputButtonClicks, "inputButtonClicks")
obs.add("addAmount", addAmount);
obs.add("changeColor", changeColor);
}
//Listen to input events and give instructions to model
var addAmount = inputTextClicks.map(function(){
console.log("Controller :: addAmount() listened to 'textClicks' and emits 'addAmount'")
return 1;
});
//Listen to button presses and give instructions to the view
var changeColor = inputButtonClicks.map(function(){
console.log("Controller :: ChangeColor() listened to 'buttonClicks' and emits 'changeColor'")
return 1;
});
Model.js
var controllerAddAmount = new Rx.Subject();
var obs = null;
//Stores the texts value. Starts at 0
var VALUE = 0;
function Model(obs){
console.log("Model :: New Model")
obs = obs
obs.observe("addAmount", controllerAddAmount, "controllerAddAmount")
obs.add("clickAmount", amountChanged)
}
//Listen to the controller about changing the value, notify the view about the new value
var amountChanged = controllerAddAmount.map(function(val){
console.log("Model :: amountChanged() listened to 'addAmount' and emits 'clickAmount'")
VALUE += val
console.log("Model :: Amount Changed to " + VALUE)
return VALUE;
})
所以问题是View.setValue()和View.setNumberColor()。
您有很多代码基本上如下所示:
// Listen to x to ...
var a = x.map(function (val) { ... });
但是你永远不会展示你用 a
做了什么。 map
采用一个可观察对象并生成一个新的可观察对象,它将 运行 提供的映射操作。然而,可观察的它 returns 是 inert 并且实际上不会做任何事情,除非你最终订阅 a
(或 a
的一些衍生物)。
对于您的控制器和模型,您最终似乎确实订阅了它们正在生成的可观察对象(通过将它们添加到您的 obs
然后在您的视图中订阅它们的迂回路线)。
但是,不清楚您是否订阅过 changeNumberColor
或 modelAmount
。根据这两个 map
方法中的命令式代码,我猜你应该在这两种情况下使用 subscribe
而不是 map
。
此外,对于 modelAmount
,您错误地使用了 last
运算符。您很可能认为 last
做了一些与实际不同的事情。
我对 Rx* 完全陌生。我正在尝试为我的论文使用 RxJS 创建 MVC 的反应版本。它大致基于 https://github.com/staltz/mvi-example
我可能应该在开始编码之前更多地研究 RxJS,但我意识到我通常只是跳到游泳池的深处才能学到最好的东西。但是现在我完全卡住了。
视图有一个带有数值的文本字段和一个按钮。按下按钮会更改文本的颜色,单击文本会迭代数值。该值存储在模型中,因此 "chain" 遍历所有三个对象(View->Controller->Model->View)。按下按钮不需要模型,所以链是View->Controller->View。
其他一切正常,但链的最后部分 (->View) 给我带来了麻烦。单击文本(在视图中)会将更改传播到控制器和模型,但不会通知视图模型中的更改。我不明白为什么,因为我理解的方式所有这些都是以相同的方式实现的。
我在下面的代码示例中添加了注释以指定不被调用的函数。
代码可用 here。请注意,就像我说的那样,代码是为了我的论文,所以一些设计决策和应用程序本身可能看起来很奇怪。下面我还尝试包括我认为最相关的部分。我知道我应该提供一个完整的例子,但在这种情况下这是不可能的。
objects获取的"obs"参数是我用来存储observables的内部数据结构。相关部分是
var OBSERVABLES = {
observe: function(source, observer, observer_name) {
this.request(source, function(s) {
console.log("\t[" + source + " is being observed by " + observer_name + " (" + s.constructor.name + " -> " + observer.constructor.name + ")]")
return s.subscribe(
function myOnNext(x) {
console.log("\t(" + source + ") " + s.constructor.name + " -> OnNext -> (" + observer_name + ") " + observer.constructor.name)
observer.onNext(x)
},
function myOnError(err) {
console.log(error)
})
})
},
View.js
var modelAmount = new Rx.Subject()
var textClicks = new Rx.Subject()
var buttonClicks = new Rx.Subject()
var changeColors = new Rx.Subject()
function View(obs, div) {
console.log("View :: New View")
obs = obs
div = div
var self = this
obs.observe("clickAmount", modelAmount, "modelAmount")
obs.observe("changeColor", changeColors, "changeColors")
obs.add("textClicks", textClicks)
obs.add("buttonClicks", buttonClicks)
//Draw HTML elements
render(div);
}
...
function onClick() {
console.log("View :: onClick() emits 'textClicks'");
textClicks.onNext()
}
function onButtonClick() {
console.log("View :: onButtonClick() emits 'buttonClicks'");
buttonClicks.onNext()
}
//Listen to controllers instruction to change the color
// DOES NOT WORK
var changeNumberColor = changeColors.map(function(c) {
console.log("View :: Listened to 'changeColor'")
if (c === undefined) {
c = getColor()
}
CONTENT.css('color', c)
});
//Listen to model's instruction to change the value
// DOES NOT WORK
var setValue = modelAmount.last(function(latestValue) {
console.log("View :: Listened to 'clickAmount'")
console.log("View :: setValue(" + latestValue + ")")
CONTENT.text(latestValue)
});
Controller.js
var inputTextClicks = new Rx.Subject();
var inputButtonClicks = new Rx.Subject();
var obs = null;
function Controller(obs){
console.log("Controller :: New Controller")
obs = obs
obs.observe("textClicks", inputTextClicks, "inputTextClicks")
obs.observe("buttonClicks", inputButtonClicks, "inputButtonClicks")
obs.add("addAmount", addAmount);
obs.add("changeColor", changeColor);
}
//Listen to input events and give instructions to model
var addAmount = inputTextClicks.map(function(){
console.log("Controller :: addAmount() listened to 'textClicks' and emits 'addAmount'")
return 1;
});
//Listen to button presses and give instructions to the view
var changeColor = inputButtonClicks.map(function(){
console.log("Controller :: ChangeColor() listened to 'buttonClicks' and emits 'changeColor'")
return 1;
});
Model.js
var controllerAddAmount = new Rx.Subject();
var obs = null;
//Stores the texts value. Starts at 0
var VALUE = 0;
function Model(obs){
console.log("Model :: New Model")
obs = obs
obs.observe("addAmount", controllerAddAmount, "controllerAddAmount")
obs.add("clickAmount", amountChanged)
}
//Listen to the controller about changing the value, notify the view about the new value
var amountChanged = controllerAddAmount.map(function(val){
console.log("Model :: amountChanged() listened to 'addAmount' and emits 'clickAmount'")
VALUE += val
console.log("Model :: Amount Changed to " + VALUE)
return VALUE;
})
所以问题是View.setValue()和View.setNumberColor()。
您有很多代码基本上如下所示:
// Listen to x to ...
var a = x.map(function (val) { ... });
但是你永远不会展示你用 a
做了什么。 map
采用一个可观察对象并生成一个新的可观察对象,它将 运行 提供的映射操作。然而,可观察的它 returns 是 inert 并且实际上不会做任何事情,除非你最终订阅 a
(或 a
的一些衍生物)。
对于您的控制器和模型,您最终似乎确实订阅了它们正在生成的可观察对象(通过将它们添加到您的 obs
然后在您的视图中订阅它们的迂回路线)。
但是,不清楚您是否订阅过 changeNumberColor
或 modelAmount
。根据这两个 map
方法中的命令式代码,我猜你应该在这两种情况下使用 subscribe
而不是 map
。
此外,对于 modelAmount
,您错误地使用了 last
运算符。您很可能认为 last
做了一些与实际不同的事情。