I never had any issues in the past with futures/promises libraries, but for some reason I can never remember how to use RxJS.
I never had any issues in the past with futures/promises libraries, but for some reason I can never remember how to use RxJS.
It basically translates to
1. Wait for a mousedown event
2. Start listening for mousemove events
2a. On each mousemove event, do something
2b. When a mouseup event occurs, stop listening for mousemoves and return to 1.
import { fromEvent } from 'rxjs';
import { exhaustMap, takeUntil, tap } from 'rxjs/operators';
const el = document.querySelector('body');
const mousedown$ = fromEvent<MouseEvent>(el, 'mousedown');
const mousemove$ = fromEvent<MouseEvent>(document, 'mousemove');
const mouseup$ = fromEvent<MouseEvent>(document, 'mouseup');
mousedown$.pipe(
exhaustMap(mousedownEvent => mousemove$.pipe(takeUntil(mouseup$))),
tap(mousemoveEvent => {
console.log('mousemove')
})
).subscribe();
https://stackblitz.com/edit/drag-and-drop-rx-rvdkzv?file=ind...---
More specifically I've found RxJS makes simple one-off calls (eg API fetches) ceremoniously painful (do I need to unsubscribe? do I get the value sync-ly or async?), but anything that involves multiple values (eg websockets, polling, event handlers) gets much cleaner.
My biggest complaint with RxJS is probably the dev experience though. It makes call stacks / the debugger useless so you have to get comfortable with console.log's everywhere. Which is one of the reasons I avoid chaining observables and filter()s in general.
Was it really a mistake or were they just using it before native promises were widely supported?
It’s not just the syntax (so (many (brackets)) and => lambdas), but it’s also really hard to create a mental model for what’s happening.
I know that react hooks are not a replacement for Rx, but really often you can program similar functionality with hooks and it’s just 10 times easier to read.
If by unintuitive you mean “Can I look at it without training and know what’s going on.” But the problems they solve are also unintuitive. Only, those issues can be buried under a tangle of nested callbacks that look correct, intuitively.
Once you take the time to really (and I mean really) understand RxJS it’s incredible. Write your own Observables. Write your own operators. Learn what the built in operators are really doing (subscriptions, etc) reimplement them yourself.
I have such an issue with this response because it just seems like “you’re holding it wrong” a la the iPhone “scandal” where apple attempted to blame an engineering flaw on its users
I would imagine most people’s use case (mine certainly is) for RxJS boils down to “call a JSON API and receive a response”. That shouldn’t be a hard problem
Imagine if someone complained about the complexity of Git and the answer was to “write your own DVCS”
The entire point of abstractions is that I don’t need to understand what’s going on underneath them
https://shift.infinite.red/redux-observable-epics-vs-redux-s...
Parent comment said:
> But the problems they solve are also unintuitive.
Do you consider calling a JSON API unintuitive or complex? If not, then you may be using the wrong tool. If you need nothing else, you are perfectly fine using a promise.
If you need to await extra requests, transform them, and react to other events then you need RxJS. For a simple call, you do not.
> I would imagine most people’s use case (mine certainly is) for RxJS boils down to “call a JSON API and receive a response”. That shouldn’t be a hard problem
Do you consider the following code hard to understand or are you are making requests in a more complex way?
``` this.network.get('<url>').subscribe(response => <do whatever you want here>) ```
Even if we agree to disagree that the above code snippet is hard to understand, you can just convert it to a promise:
``` const response = await lastValueFrom(this.network.get('<url>')) ```
http$
.pipe(
map(res => res['payload']),
catchError(err => {
console.log('caught mapping error and rethrowing', err);
return throwError(err);
}),
finalize(() => console.log("first finalize() block executed")),
catchError(err => {
console.log('caught rethrown error, providing fallback value');
return of([]);
}),
finalize(() => console.log("second finalize() block executed"))
)
.subscribe(
res => console.log('HTTP response', res),
err => console.log('HTTP Error', err),
() => console.log('HTTP request completed.')
);
Once you see the output it begins to finally make sense but intuitive it is notOnce you learn how RxJS works examples like the one anbove anre intuitive.
Angular 2’s most egregious crime is that their tutorials try to make it (and RxJS) seem “simple”. They aren’t. They’re powerful.
2) RxJS is not Git. It’s a library designed to be extended by users. To use RxJS you need to write code with it. Git is not exclusively a library and doesn’t require you to write you own extensions to use it day to day.
As a casual Git user you wouldn’t get much out of implementing a DVCS but you would benefit from learning to host your own repo instead of relying on GitHub.
If someone was struggling to use Git I’d tell them to learn the foundations, practice them, and then to host their own repos to continue learning.
The same basic track I recommended for RxJS.
A big moment for RxJS users is when they realize that they need an operator or observable that doesn’t exist. It’s really fun to write your own.
I am doing that all the time and all it takes, is withLatestFrom or combineLatest
The biggest thing for me is the realization of the "source of truth". With observables, if they are set up correctly, you can see the exact bits of information that some resultant stream are dependent upon. Operations then can have a single action because all of those sources can be muxed together rather than having several calls throughout a component to doSomeAction().
I disagree. I have implemented several use cases using RxJS which would have otherwise been significantly more difficult to solve. (Think timing parallel sequences of animations und other UX effects etc.)
If anyone still cares about this, here is a helpful site that you can understand without knowing anything about RxJS: https://rxmarbles.com/
When I first started learning that sort of thing it made no sense at all. But now it's just a design pattern that allows you to organize things. Having that understanding helps abstract away some of the mechanisms in the observable.
It helped me at least. YMMV
JS Promises are not completely monadic though, because a Promise that resolves into a Promise is always effectively auto-flattened into a single Promise. But most of the time other monadic properties of Promises can be used despite this.
ChatGPT is actually pretty good at exploring these different styles btw. It is pretty good at taking one code example and implementing it in different ways when prompted.
I've found that this is one of those things that half of the developers never learn to use properly and is therefore a net negative.
In Angular specifically it offers a spectrum of footguns, my favourite by far being passing an observable as an input.
Will the component re-render when the observable emits? Who knows? It depends on more than one factor.
Interesting things also happen when it's a cold observable, it errors out or just completes.
Overall it's quite the circus and I've been in teams where most of the developers had only a surface understanding of what was going on.
That in and of itself is actually not a showstopper until someone decides to create their own component library.
Anyhow, there's definitely a learning curve but what it provides is very powerful. It's unfortunate, IMO, that the API has become less approachable over the years.
It’s great for what it’s designed for, but you’re not wrong either. Composition can be hard to manage and navigate where a chainable API can be easy to follow and interpret by simply reading the flow.
I think RxJS is actually amazing and I like the path they chose, but I see why it isn’t more widely adopted too. It isn’t nearly as intuitive as it maybe could be.
However, I found the API choices odd because in RxJS the `.pipe` operator is, itself, chained rather than being standalone. Using a standalone `pipe`, such as via Ramda or something home-grown worked just fine, so I found it very strange that they mixed the functional composition style with the object-chainable style.
> I see why it isn’t more widely adopted too
I agree that RxJS is amazing, which is why less adoption is unfortunate. So many projects would benefit from RxJS or something like it.
Subscribe, (value) => currentValue = value, do some calculation, onDestroy unsubscribe..
I don't know whether people really solve complex problems or whether they just appear complex when you use RxJS.