Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subject and BehaviorSubject — for frameworks and UI libs #186

Open
dariomannu opened this issue Dec 9, 2024 · 2 comments
Open

Subject and BehaviorSubject — for frameworks and UI libs #186

dariomannu opened this issue Dec 9, 2024 · 2 comments
Labels
possible future enhancement An enhancement that doesn't block standardization or shipping

Comments

@dariomannu
Copy link

So far this proposal is evolving in an interesting way, but it appears to cater mostly for the "direct" use, in which developers call EventTarget.when from application code.

In the context of UI libraries and frameworks that want to support Observables there may be a few things that could turn very useful.

The issue is that we often need to subscribe to Observables that don't exist yet, when running as part of templates or UI components.

Take the following example, based on a usage pattern being currently pioneered by Rimmel.js:

import { BehaviorSubject, scan } from 'rxjs';
import { rml } from 'rimmel';

const Component = () => {
  const count = new BehaviorSubject(0).pipe(
    scan(x => x+1)
  );
  
  return rml`
    <button onclick="${count}">click me</button> <br>
    <button onclick="${count}">or me</button> <br>

    Clicked <span>${count}</span> times.<br>
    Yes, I repeat: you clicked it <span>${count}</span> times.<br>
  `;
};

document.body.innerHTML = Component();

As you can see, in the component above we have a stream called count, which libraries like Rimmel can plug both ways to the DOM: on the input side to the event source, on the output side as sinks, back to the DOM.

It would be a bit challenging to implement the above without the use of Subject and/or BehaviorSubject, without magic constructs like "Forward Refs" (=proxies) and without sacrificing ergonomics (mainly) or performance (secondarily, because of proxies).

These two primitives both act as central points of reference in the data flow. If we think entirely in streams, we need to be able to connect them from multiple sources (e.g.: from two different buttons, like above), to multiple targets (again, two span tags like above). This way we can isolate side effects and leave them with the framework.

In the component code (which only runs once, before the component is rendered unlike in React where it runs for every update), as we don't yet have access to the observable coming from the DOM, we use this BehaviorSubject as a temporary connector.

I have a Stackblitz example that shows this in action.

Unfortunately, we can only go as far as connecting the native Observable to the BehaviorSubject, so RxJS has to take over the stream very quickly and developers can have little interaction (=none) with the original, native Observable:

[Event Target (onclick)] => [DOM Observable] => [Rx.BehaviorSubject (count)] => [ops] => [sink (innerHTML)]

That would leave little motivation to use DOM Observables.
Thoughts? Can we not just have Subject and BehaviorSubject in the spec?

@petamoriken
Copy link

Perhaps what you are looking for is the Signals proposed on the language specification side.
https://github.com/tc39/proposal-signals

@dariomannu
Copy link
Author

No, that's exactly what I'm trying to steer clear of. Observables enable functional-reactive programming, whilst Signals are the antithesis of all this.

@domfarolino domfarolino added the possible future enhancement An enhancement that doesn't block standardization or shipping label Dec 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
possible future enhancement An enhancement that doesn't block standardization or shipping
Projects
None yet
Development

No branches or pull requests

3 participants