github stackblitz/alien-signals v2.0.0

latest releases: v2.0.7, v2.0.6, v2.0.5...
4 months ago

Version 2.0 rethinks and optimizes the reactive system model, with minimal impact on users who only use the surface APIs. If you extend or deeply utilize alien-signals, please pay attention to the "Reactive Model Refactor" section.

Changes to Surface APIs

  • Added four new APIs: getCurrentSub, setCurrentSub, getCurrentScope, setCurrentScope

Deferred Signal Value Evaluation

Differences from v1

In v1, assigning a value to a signal immediately propagated the Dirty flag, causing some computed values to be unnecessarily re-evaluated.

// v1
const src = signal(10);
const double = computed(() => src() * 2);

double(); // -> 20

src(999); // double.flags -> Dirty
src(10);  // no effect

double(); // -> 20 (recomputed unnecessarily)

In v2, assigning a value to a signal only propagates the Pending flag, reducing unnecessary recomputation. Actual evaluation occurs during the next read.

// v2
const src = signal(10);
const double = computed(() => src() * 2);

double(); // -> 20

src(999); // src.flags -> Dirty, double.flags -> Pending
src(10);  // no effect

double(); // Checks src state -> unchanged, no recomputation needed

Effect Scope Parent-Child Hierarchy

In v2, recursive cleanup is achieved through a parent-child structure:

const scope1 = effectScope(() => {
	const scope2 = effectScope(() => {
		effect(() => ...);
		computed(() => ...);
	});
});

scope1();

Calling scope1() automatically cleans up its child scope scope2.

To make scope2 independent of scope1, temporarily set activeScope = undefined manually:

const scope1 = effectScope(() => {
	const prev = setCurrentScope(undefined);
	const scope2 = effectScope(() => {
		effect(() => ...);
		computed(() => ...);
	});
	setCurrentScope(prev);
});

Reactive Model Refactor

  • Merged Subscriber and Dependency into ReactiveNode
  • Trigger unwatched(dep) when all subscribers are lost, without recursively clearing subsequent subscribers
  • propagate now only propagates Pending; to immediately mark Dirty, call propagate + shallowPropagate after assignment
  • Adjusted naming for EffectFlags and ReactiveFlags; removed unused flags

Updated Options and APIs

  • notifyEffectnotify
  • updateComputedupdate
  • Added the unwatched option for custom handling when all subscribers are lost
  • Removed processEffectNotifications, processComputedUpdate, processPendingInnerEffects, updateDirtyFlag
  • Added unlink, checkDirty

For performance differences, please refer to js-reactivity-benchmark.

Contributors

Thanks~

Special Sponsor

Next Generation Tooling

Platinum Sponsors

An approachable, performant and versatile framework for building web user interfaces.

Stay in the flow with instant dev experiences.
No more hours stashing/pulling/installing locally

— just click, and start coding.

Essential tools for software developers and teams.

Silver Sponsors

You?

Don't miss a new alien-signals release

NewReleases is sending notifications on new releases.