proposal-signals / signal-polyfill

Implementation tracking the current state of https://github.com/tc39/proposal-signals
Apache License 2.0
185 stars 13 forks source link

Computed breaks if dependency is set after being unwatched by a Watcher #27

Open justinfagnani opened 1 month ago

justinfagnani commented 1 month ago

Reproduction: https://stackblitz.com/edit/signal-polyfil-unwatch-bug?file=src%2Fmain.ts

If a computed is watched by a watcher, then a dependency is updated, then the computed is re-watched by the watcher, the computed will not update.

const count = new Signal.State(0);
const countPlusOne = new Signal.Computed(() => {
  return count.get() + 1;
});

const watcher = new Signal.subtle.Watcher(() => {
  watcher.watch();
});

watcher.watch(countPlusOne);

console.log('expected 1, got', countPlusOne.get());
count.set(1);
console.log('expected 2, got', countPlusOne.get());

watcher.unwatch(countPlusOne);
count.set(2);
// If this line is removed, the computed works.
watcher.watch(countPlusOne);

// Reading countPlusOne here gives an incorrect value of 2!
console.log('expected 3, got', countPlusOne.get());
justinfagnani commented 2 weeks ago

As a workaround in cases where you need to unwatch and re-watch, you can throw away the computed and create a fresh one.

divdavem commented 1 week ago

For info, this issue is the same as https://github.com/tc39/proposal-signals/issues/216, it is fixed by #16