[@lit-labs/signals] signal set() in firstUpdated does not cause a rerender.
Which package(s) are affected?
@lit-labs/signals
Description
signal set() in firstUpdated does not cause a rerender.
Reproduction
https://stackblitz.com/edit/vitejs-vite-gqki2ufj?file=src%2Fsimple-counter.ts&terminal=dev
Workaround
But if i wait a tick, it rerenders.
protected firstUpdated(): void {
requestAnimationFrame(() => {
this.#value.set(1);
});
}
Affected versions
@lit-labs/signals v0.1.2
Browser/OS/Node environment
Browser: Chrome 134.0.6998.167
We're computing the entire update (performUpdate) inside a single computed so I believe any sets to dependent signals in there will not trigger another computation.
The way we denote if a change will prompt an update is with a flag isUpdatePending; and the way performUpdate is factored, that flag is set in the middle before we call firstUpdated/updated. That's not conveniently compatible with the need here.
Probably the simplest fix (taking advantage of the fact the we just need to control the work at the end of performUpdate) would be to override _$didUpdate (which is @internal) such that it bails when called normally (part of performUpdate) and is called after it by SignalWatcher. Something like:
@justinfagnani wdyt?
// ...
this.__performUpdateSignal = new Signal.Computed(() => {
this.__forceUpdateSignal.get();
super.performUpdate();
const changes = this.__updateChanges;
this.__updateChanges = undefined;
if (changes !== undefined) {
super._$didUpdate(changes);
}
});
// ...
__updateChanges?: PropertyValues;
_$didUpdate(changes) {
this.__updateChanges = changes;
}
Note that you can workaround this issue by using the watch directive to render the signal. See this updated example.
This works because the watch directive separately tracks signals.