Signals library for Dark
npm install @dark-engine/signalscomputed does not subscribe itself to effects. Instead, when an effect uses a computation, the subscription is forwarded to the source signals that the computation depends on.
npm install @dark-engine/signals
`
yarn:
`
yarn add @dark-engine/signals
`
CDN:
`html
`
Usage
`tsx
const count$ = signal(0);
effect(() => {
console.log('count:', count$.get());
});
const App = component(() => (
<>
Count: {count$.get()}
>
));
`
API
`tsx
import {
type Signal,
type Computed,
type Effect,
signal,
computed,
effect,
useSignal,
useComputed,
useSignalEffect,
useSelected,
VERSION,
} from '@dark-engine/signals';
`
$3
Creates a reactive value.
`tsx
const count$ = signal(0);
count$.set(1);
count$.set(2);
console.log(count$.get()) // 2
`
peek method reads value without any subscription
`tsx
console.log(count$.peek()) // 2
`
$3
Creates a lazy computed value, automatically tracks dependencies.
`tsx
const count$ = signal(1);
const double$ = computed(() => count$.get() * 2);
count$.set(1);
count$.set(2);
console.log(double$.get()) // 4
`
$3
Creates a side effect that automatically runs when dependencies change.
`tsx
const count$ = signal(1);
effect(() => {
console.log('count:', count$.get());
});
count$.set(x => x + 1);
count$.set(x => x + 1);
// effect prints 'count: 1'
// effect prints 'count: 2'
// effect prints 'count: 3'
`
$3
Hook for creating a signal inside a Dark component. The signal preserves its state between component renders.
`tsx
const App = component(() => {
const count$ = useSignal(0);
return (
<>
Count: {count$.get()}
>
);
});
`
$3
Hook for creating a computed value inside a component. Automatically recalculates when dependencies change.
`tsx
const App = component(() => {
const count$ = useSignal(1);
const double$ = useComputed(() => count$.get() * 2);
return (
<>
Count: {count$.get()}
Double: {double$.get()}
>
);
});
`
$3
Hook for creating an effect inside a component. The effect automatically subscribes to signals and computeds used inside the function.
`tsx
const App = component(() => {
const value$ = useSignal('hello');
useSignalEffect(() => {
console.log('value changed:', value$.get());
});
return (
<>
value={value$.get()}
onInput={e => value$.set(e.target.value)}
/>
Value: {value$.get()}
>
);
});
`
Blow your mind
What will happen when this code runs? An infinite loop?
`tsx
const a$ = signal(0);
effect(() => {
console.log(a$.get());
a$.set(x => x + 1);
});
`
In other signal implementations (Solid, Preact, etc.) - yes.
But in Dark, only one line will be printed to the console. And all this happens synchronously in one tick of the event loop.
`tsx
// 0
`
And here?
`tsx
const a$ = signal(1);
const b$ = computed(() => a$.get() + 1);
const c$ = computed(() => b$.get() + 1);
effect(() => {
a$.set(c$.get());
console.log('a:', a$.get(), 'b:', b$.get(), 'c:', c$.get());
});
`
The same
`tsx
// a: 3 b: 4 c: 5
``