tc39 / proposal-signals

A proposal to add signals to JavaScript.
MIT License
2.95k stars 54 forks source link

Should some EventTargets also be Signals? #137

Open NotWoods opened 1 month ago

NotWoods commented 1 month ago

Some DOM event targets (such as MediaQueryList, returned by matchMedia as well as AbortSignal) have a single property and a single event that emits whenever that property's value changes. While signals could be offered as a second property, it might also be nice to have some way for a class to inherit both EventTarget and Signal.

const mql = window.matchMedia('(max-width: 900px)');
const isSmallScreen = new Signal.Computed(() => mql.get());

I'm also really happy to see Signal.subtle.watched/Signal.subtle.unwatched which makes it pretty easy to wrap these APIs in userland :) It's missing from a lot of framework Signal libraries.

function matchMediaSignal(query) {
  const mql = window.matchMedia(query);
  const abortController = new AbortController();

  const signal = new Signal.State(mql.matches, {
    [Signal.subtle.watched]() {
      this.set(mql.matches);
      mql.addEventListener('change', () => this.set(mql.matches), { signal: abortController.signal });
    },
    [Signal.subtle.unwatched]() {
      abortController.abort();
    }
  });
}
nuxodin commented 1 month ago

similiar issue: https://github.com/proposal-signals/proposal-signals/issues/88 Thank you for adding a use case.

littledan commented 1 month ago

This is an excellent question and corresponds much more closely to how I would like to see signals integrate with the web platform than #88. @wycats was telling me about an idea for ResizeObserver to integrate with signals in a similar way. Let’s develop more examples of how this integration should look—it is nice to see that the signal versions of web APIs can be built as a library on top, as demonstrated above.

wycats commented 1 month ago

For what it's worth, I think the critical question is not whether the EventEmitter emits an event with a single value when the value changes, but rather whether it's safe to ignore intermediate values until you're ready to use them in another computation.

(In my opinion, if a lossless stream of intermediate values are important, Observables are a much more effective abstraction).

That said, I think it is quite common for Signal-like modelling to make sense for situations that currently use EventEmitter and I think it's a wide open design space for exploration.

Broadly speaking, I think the *Observer DOM APIs are the strongest initial candidates, because those APIs are already intended to be used in discrete ways (and intentionally batch up changes until a particular phase in the rendering pipeline).