Skip to content

Models and actions

Use upstream Preact Signals models and actions from @kamod-ch/signals.

Models and actions#

@kamod-ch/signals re-exports the official model and action APIs from @preact/signals.

Kamod does not reimplement these primitives. Use them exactly like the upstream Preact Signals APIs, and add Kamod persistence only when you need durable state.

Imports#

import {
  action,
  computed,
  createModel,
  signal,
  useModel,
} from "@kamod-ch/signals";

Create a model#

import { computed, createModel, signal } from "@kamod-ch/signals";

export const CounterModel = createModel((initialCount = 0) => {
  const count = signal(initialCount);
  const doubled = computed(() => count.value * 2);

  return {
    count,
    doubled,
    increment() {
      count.value += 1;
    },
  };
});

Functions returned from a model are wrapped by upstream Signals as actions, so related updates are batched.

Use a model in Preact#

import { useModel } from "@kamod-ch/signals";
import { CounterModel } from "./CounterModel";

export function Counter() {
  const counter = useModel(() => new CounterModel(1));

  return (
    <button onClick={counter.increment}>
      Count: {counter.count} / doubled: {counter.doubled}
    </button>
  );
}

useModel() creates the model for the component and disposes model effects when the component unmounts.

Explicit actions#

You can also create standalone actions:

import { action, signal } from "@kamod-ch/signals";

const first = signal(0);
const second = signal(0);

export const updateBoth = action((value: number) => {
  first.value = value;
  second.value = value;
});

Relationship to persisted signals#

Models are the composition layer. Persisted signals are still available for small durable values:

import { persistedSignal } from "@kamod-ch/signals";

export const theme = persistedSignal("theme", "dark", { storage: "local" });

A future createPersistedModel() API will combine official models with Kamod storage drivers. Until then, use models for reactive structure and persistedSignal() for individual persisted values.