proposal-signals / signal-utils

MIT License
69 stars 6 forks source link

Utilities to Implement #15

Open NullVoxPopuli opened 2 months ago

NullVoxPopuli commented 2 months ago

Blocked on framework-specific semantics and timing (cleanup)

justinfagnani commented 2 months ago

It would be nice to have a utility similar to MobX's reaction() function.

reaction() is very useful when you need to track the pervious value of a signal. You give it a tracked data function and an untracked effect function that's run when the value changes.

Something a bit like this:

export const reaction = <T>(
  data: () => T,
  effect: (value: T, previousValue: T) => void,
  equality = Object.is,
) => {
  const computed = new Signal.Computed(data);
  let previousValue = computed.get();
  let isReacting = false;
  const watcher = new Signal.subtle.Watcher(async () => {
    if (isReacting === true) {
      return;
    }
    isReacting = true;
    await 0;
    isReacting = false;
    const value = computed.get();
    if (!equality(previousValue, value)) {
      effect(value, previousValue);
      previousValue = value;
    }
  });
  watcher.watch(computed);
};
NullVoxPopuli commented 2 months ago

oo nice! that does seem useful -- I know quite a few folks that would like such a utility for caching or memoizing complex calculations (tho I don't know an exact use case, but I know it's desired!).

Would you be willing to submit a PR adding this utility along with a bunch of tests? (so we can ensure behavior is retained as the polyfill (and spec) evolves?)

JosXa commented 2 months ago

Reminds me of Vue's watch function that allows to declare multiple signals ("refs") to track: https://vuejs.org/api/reactivity-core.html#watch