Using Stores in Components#

A store factory returns a live instance whose state is signal-backed. When you read store.state.x inside a component's render function, SignalX tracks the dependency and re-renders that component whenever the value changes. This guide covers reading, sharing, lifetimes, and cleanup.

Reading state in render#

Call the factory inside a component(...) setup and reference the state in the returned render function. No manual subscription is needed for rendering.

TSX
Loading preview...

Derived values in render#

Computed getters exposed under get are read with .value. They update automatically as the underlying state changes.

TSX
Loading preview...

Reacting to specific mutations#

To run side effects when a single property changes, subscribe to its onMutated{Key} event. Each subscribe returns a Subscription you can unsubscribe() later.

TSX
const store = useCounterStore();

const sub = store.events.onMutatedCount.subscribe(value => {
    document.title = `Count: ${value}`;
});

// later, when you no longer need it:
sub.unsubscribe();

Subscribe to action lifecycle events the same way for cross-cutting concerns like logging or analytics:

TSX
store.actions.onFailure.someAsyncAction.subscribe((error, ...args) => {
    reportError(error, args);
});

Sharing one instance vs. fresh instances#

The third argument to defineStore is the instance lifetime, defaulting to Scoped:

TypeScript
import { defineStore } from '@sigx/store';
import { InstanceLifetimes } from '@sigx/runtime-core';

const useAppStore = defineStore('app', setup, InstanceLifetimes.Singleton);
  • Scoped (default) — shared within the current resolution scope.
  • Singleton — one shared instance across the whole app; ideal for global app state.
  • Transient — a new instance every time the factory is called.

Pick Singleton when several components must read and write the same state. Pick Transient when each component should own an isolated copy.

Parameterized stores#

A setup can accept up to five extra parameters after the context. Those parameters are forwarded through the factory call, letting you seed a store per instance.

TSX
import { defineStore } from '@sigx/store';

const useListStore = defineStore('list', ({ defineState }, initialItems: string[]) => {
    const { state, mutate } = defineState({ items: initialItems });
    return { state, mutate };
});

// create instances seeded with different data
const left = useListStore(['a', 'b']);
const right = useListStore(['x', 'y', 'z']);

Cleanup and lifetime#

When you create a store instance inside a component, it is tied to that component's lifecycle. On unmount the instance auto-disposes: its effect scope is stopped and all event topics are destroyed, so onMutated* and action events stop firing.

If you create an instance outside a component, dispose it yourself when you are done:

TypeScript
const store = useCounterStore();
store.state.count = 1; // subscribers fire

store.dispose();        // stop scope + destroy topics
store.state.count = 2;  // subscribers no longer fire

Next steps#