Features
- Effect cleanup functions — Effects can now return a cleanup function that runs before each re-execution and on disposal (#113)
effect(() => { const handler = () => { /* ... */ }; document.addEventListener('click', handler); return () => document.removeEventListener('click', handler); });
Bug Fixes
- Fix
checkDirtyresilient to graph mutations during update (#109, #110) - Fix
effectScopenot participating in propagation (#111) - Fix inner write blocking future propagation through computed chain (#112)
- Fix dispose cleanup running inside tracking context — cleanup reads no longer create spurious dependencies
Note for Custom API Implementors
If you implement custom effect/computed execution using createReactiveSystem, you must wrap the execution body with ++runDepth / --runDepth. This counter drives the innerWrite parameter to propagate, which provides two directions of protection:
- Self-protection — the currently-running subscriber (marked
RecursedCheck) won't be re-triggered by its own write - Downstream protection — other subscribers are marked
Recursedduring inner writes, which acts as a bookmark for the propagation state machine. Without this mark, subsequent top-level writes will see stale flags and skip propagation through computed chains — this is the bug fixed in #112
Testing
Integrate reactive-framework-test-suite — a cross-framework conformance suite with 180 test cases across 13 reactive libraries. alien-signals is the only framework that passes all 180 tests (#114).
| Framework | Pass / 180 |
|---|---|
| alien-signals | 180 |
| @preact/signals-core | 178 |
| @vue/reactivity | 172 |
| anod | 166 |
| tansu | 163 |
| @solidjs/signals | 161 |
| solid-js | 154 |
| mobx | 148 |
| signal-polyfill (TC39) | 145 |
| @angular/core | 141 |
| svelte | 131 |
| S.js | 130 |
| @reactively/core | 114 |