Fix upload wizard tab crash: dispatch must not track the model signal
createUploadController runs an effect() that calls dispatch. store.ts dispatch was `model.set(update(model(), msg))` — the reactive model() read made the effect depend on its own write and re-schedule forever, livelocking the main thread. Angular's NG0103 guard doesn't cover effect self-rescheduling, so no error was thrown; Firefox just killed the unresponsive tab. Only /registreren and /herregistratie (which mount the upload controller) were affected. dispatch now uses model.update((m) => update(m, msg)) — the current value is read untracked, so no effect can loop on its own dispatch. Hardens all wizard stores. Adds a regression spec. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,10 @@ export function createStore<Model, Msg>(
|
||||
const model = signal(init);
|
||||
return {
|
||||
model: model.asReadonly(),
|
||||
dispatch: (msg) => model.set(update(model(), msg)),
|
||||
// Use `.update` (raw current value, no tracked read) not `set(update(model(), …))`:
|
||||
// dispatch is a command and must never subscribe its caller to `model`. Reading
|
||||
// `model()` here inside an effect that also dispatches makes the effect depend on
|
||||
// its own write and livelock the main thread (crashed the upload wizards).
|
||||
dispatch: (msg) => model.update((m) => update(m, msg)),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user