Closed xgrommx closed 9 years ago
Could someone help me?
@xgrommx we already have an equivalent to Bacon.when
with Rx.Observable.when
Such code could be written as such without using jQuery:
function $$(elementString) {
return document.querySelector(elementString);
}
function click(element) {
return Rx.Observable.fromEvent(element, 'click');
}
function onLoad () {
var $display = $$('#display');
function getValue() {
return +$$('#display').textContent;
}
var $plusClick = click($$('#plus')).map(getValue),
$minusClick = click($$('#minus')).map(getValue),
$resetClick = click($$('#reset'));
var $updates = Rx.Observable.when(
$plusClick.thenDo(function (x) { return x + 1; }),
$minusClick.thenDo(function (x) { return x - 1; }),
$resetClick.thenDo(function () { return 0; })
).startWith(0);
$updates.subscribe(function (x) {
$display.textContent = x;
});
}
window.onload = onLoad;
As I understood, if I will use startWith
I will have Bacon.update
. Also I have one small question, if I want use composition of two or many observables in condition like in Bacon.update
https://github.com/baconjs/bacon.js/#join-patterns-and-baconbus how can I solve it? For example this http://en.wikipedia.org/wiki/Dining_philosophers_problem
Sorry, I found that Rx already have an operator and
. I think this operator is just right.
@mattpodwysocki I think this is good example for demonstration how user could use a when
operator:
var chopsticks = [new Rx.Subject(), new Rx.Subject(), new Rx.Subject()];
var hungry = [new Rx.Subject(), new Rx.Subject(), new Rx.Subject()];
var eat = i => {
return () => {
setTimeout(() => {
console.log('Done');
chopsticks[i].onNext({});
chopsticks[(i+1) % 3].onNext({});
}, 1000);
return 'philosopher ' + i + ' eating';
};
};
var dining = Rx.Observable.when(
hungry[0].and(chopsticks[0]).and(chopsticks[1]).thenDo(eat(0)),
hungry[1].and(chopsticks[1]).and(chopsticks[2]).thenDo(eat(1)),
hungry[2].and(chopsticks[2]).and(chopsticks[0]).thenDo(eat(2))
);
dining.subscribe(console.log.bind(console));
chopsticks[0].onNext({}); chopsticks[1].onNext({}); chopsticks[2].onNext({});
for (var i = 0; i < 3; i++) {
hungry[0].onNext({}); hungry[1].onNext({}); hungry[2].onNext({});
}
@xgrommx that's great! If you'd like to turn it into an official example with a web page, we'd be more than happy to accept it!
@mattpodwysocki Oh sure I can added it to the official documentation and to my rx book.
@mattpodwysocki thank you for answering this question, but let me ask you one more to make this topic complete.
How do i get prev state of .when stream inside its functions? In other words how to transpile following example to Rx?
var foo = Bacon.update([],
[bar], function (prevFoo, barValue) {
return prevFoo.concat(barValue);
}
[baz], function (prevFoo, bazValue) {
// remove bazValue from prevFoo here
return prevFooWithoutBazValue;
}
);
I'm not very familiar with the Bacon
example, but your best bets are
bufferWithCount(2)
or possibly
reduce
@gyzerok If you look inside update
method from Bacon you can found scan
. I just try reproduce this operator in Rx and I use it so:
let PersonStore = Rx.Observable.when(
Actions.changeFirstName.debounce(2000).thenDo(firstName => person => person.set('firstName', firstName)),
Actions.changeLastName.thenDo(lastName => person => person.set('lastName', lastName)),
Actions.changeCountry.thenDo(country => person => person.setIn(['country', 'name'], country)),
Actions.addFriend.thenDo(friend => person => person.set('friends', person.get('friends').push(friend))),
Actions.save.debounce(2000).thenDo(_ => person => {
console.log(person.toJS());
return person;
})
).scan(I.fromJS(defaultPerson), (person, action) => action(person)).publishValue(I.fromJS(defaultPerson)).refCount();
We can pass callback function to scan
method. publishValue(I.fromJS(defaultPerson)).refCount()
is alternative for Bacon.toProperty(I.fromJS(defaultPerson))
@xgrommx Thank you for your answer! May I ask you to convert my particular example from Bacon to Rx? So I can get it right.
@gyzerok Welcome! As you can see person
is previous value, action(person)
is new value. Maybe in the future I could find more better example but now I use it. If you have some questions I'll try answer =) By the way the method update
exists only in Bacon and make this library unique.
@xgrommx I cannot find any information about thenDo
method in the docs. Is it deprecated?
And I cant understand where in the following code person
comes from
Actions.changeFirstName.debounce(2000).thenDo(firstName => person => person.set('firstName', firstName))
@xgrommx I guess I get general solution for this. Mb it can be better?
function update(initial, ...patterns) {
const streams = patterns.filter((_, i) => i % 2 === 0);
const callbacks = patterns.filter((_, i) => i % 2 !== 0);
const pairs = streams.map((_, i) =>
[streams[i], callbacks[i]]
);
return Rx.Observable.when.apply(this, pairs.map(p =>
p[0].thenDo(data => prev => p[1](prev, data))
)).scan(initial, (prev, f) => f(prev));
}
Test code:
let a = new Rx.Subject();
let b = new Rx.Subject();
let test = update(0,
a, (prev, data) => prev + data,
b, (prev, data) => prev - data
);
test.subscribe(console.log.bind(console));
a.onNext(1);
a.onNext(5);
b.onNext(3);
b.onNext(2);
@gyzerok You can look on this http://xgrommx.github.io/rx-book/content/observable/observable_instance_methods/thendo.html
@gyzerok This is my alternative for Bacon.update https://github.com/xgrommx/react-rx-flux/blob/master/src/store.js#L7. Can use array of observables as in Bacon.update
.
Hello @mattpodwysocki,
What is alternative in Rx for Bacon.update or Bacon.when? I guess that it's very helpful operator. Small example for a simple counter http://jsbin.com/jenanuceme/1/edit?html,js,output