Astro-DX Logo Astro-DX
GitHub
@astro-dx/core

Signals

signal(), computed(), effect() — same API as Angular 20+

Counter — signal + computed
0 count
+
0 double
neutral sign
Reset

Code example

"code-keyword">import { computed, signal } "code-keyword">from '@astro-dx/core';
"code-keyword">import { getElement } "code-keyword">from '@astro-dx/dom';
"code-keyword">import { onClick } "code-keyword">from '@astro-dx/events';

"code-keyword">const count = "code-function">signal(0);
"code-keyword">const double = "code-function">computed(() => "code-function">count() * 2);

"code-function">getElement('#count-display')."code-function">text(count);
"code-function">getElement('#double-display')."code-function">text(double);

"code-function">onClick('#btn-inc', () => count."code-function">update((v) => v + 1));
"code-function">onClick('#btn-dec', () => count."code-function">update((v) => v - 1));
Dynamic deps — conditional effect + peek()

Change branch between A/B and verify re-tracking. Updating peek-only value must not re-run the effect.

Use A Use B A +1 B +10 Peek value +1
Branch
A
Selected value
0
Effect runs
0
A source
1
B source
100

Peek-only signal value: 0

Conditional dependencies snippet

"code-keyword">import { effect, signal } "code-keyword">from '@astro-dx/core';

"code-keyword">const useA = "code-function">signal("code-type">true);
"code-keyword">const a = "code-function">signal(1);
"code-keyword">const b = "code-function">signal(100);

"code-function">effect(() => {
  "code-keyword">if ("code-function">useA()) {
    console."code-function">log('branch A', "code-function">a());
  } "code-keyword">else {
    console."code-function">log('branch B', "code-function">b());
  }
});

useA."code-function">set("code-type">false);
b."code-function">set(120);
a."code-function">set(2);

peek() best practices

"code-keyword">import { effect, signal } "code-keyword">from '@astro-dx/core';

"code-keyword">const visible = "code-function">signal("code-type">true);
"code-keyword">const total = "code-function">signal(99);
"code-keyword">const title = "code-function">signal('Cart');

"code-function">effect(() => {
  "code-keyword">if (!"code-function">visible()) "code-keyword">return;

  "code-keyword">const trackedTitle = "code-function">title();

  "code-keyword">const currentTotal = total."code-function">peek();

  console."code-function">log(`${trackedTitle}: ${currentTotal}`);
});

Playground

Edit the code and hit Run to see it live. The preview uses a shimmed version of the astro-dx API.

With astro-dx Without
"code-keyword">import { computed, signal } "code-keyword">from '@astro-dx/core';
"code-keyword">import { getElement } "code-keyword">from '@astro-dx/dom';
"code-keyword">import { onClick } "code-keyword">from '@astro-dx/events';

"code-keyword">const count = "code-function">signal(0);
"code-keyword">const double = "code-function">computed(() => "code-function">count() * 2);
"code-keyword">const sign = "code-function">computed(() => ("code-function">count() > 0 ? 'positive' : "code-function">count() < 0 ? 'negative' : 'neutral'));

"code-function">getElement('#count-display')."code-function">text(count);
"code-function">getElement('#double-display')."code-function">text(double);
"code-function">getElement('#sign-display')."code-function">text(sign);

"code-function">onClick('#btn-inc', () => count."code-function">update((v) => v + 1));
"code-function">onClick('#btn-dec', () => count."code-function">update((v) => v - 1));
"code-function">onClick('#btn-reset', () => count."code-function">set(0));
"code-keyword">import { atom, computed } "code-keyword">from 'nanostores';

"code-keyword">const $count = "code-function">atom(0);
"code-keyword">const $double = "code-function">computed($count, (c) => c * 2);
"code-keyword">const $sign = "code-function">computed($count, (c) => (c > 0 ? 'positive' : c < 0 ? 'negative' : 'neutral'));

$count."code-function">subscribe((v) => {
  "code-keyword">const el = document."code-function">querySelector('#count-display');
  "code-keyword">if (el) el.textContent = "code-function">String(v);
});

$double."code-function">subscribe((v) => {
  "code-keyword">const el = document."code-function">querySelector('#double-display');
  "code-keyword">if (el) el.textContent = "code-function">String(v);
});

$sign."code-function">subscribe((v) => {
  "code-keyword">const el = document."code-function">querySelector('#sign-display');
  "code-keyword">if (el) el.textContent = v;
});

document."code-function">querySelector('#btn-inc')?."code-function">addEventListener('click', () => $count."code-function">set($count."code-function">get() + 1));

document."code-function">querySelector('#btn-dec')?."code-function">addEventListener('click', () => $count."code-function">set($count."code-function">get() - 1));

document."code-function">querySelector('#btn-reset')?."code-function">addEventListener('click', () => $count."code-function">set(0));