@zeix/cause-effect
Version:
Cause & Effect - reactive state management primitives library for TypeScript.
127 lines (94 loc) • 4.13 kB
Markdown
---
title: "Getting Started"
description: "Learn what Cause & Effect is, why it exists, and how to build your first reactive graph."
---
Cause & Effect is a framework-agnostic TypeScript library for building fine-grained reactive state, derived values, async tasks, and keyed composite data structures in one signal graph.
- Application state usually splits into separate tools for sync values, async loading, collections, and side effects, which creates duplicated mental models.
- Framework-level effects and selectors often depend on manual dependency lists, manual loading flags, or ad-hoc memoization that drifts from the real data flow.
- Dynamic structures such as nested objects, keyed arrays, and external event streams are easy to make reactive incorrectly or inefficiently.
- Integration layers such as custom elements or framework adapters need stable reactive primitives without adopting a full rendering framework.
Cause & Effect exposes a small set of signal primitives that all participate in the same graph. `createState()` owns mutable values, `createMemo()` and `createTask()` derive sync and async values, `createEffect()` reacts to them, and `createStore()`, `createList()`, `createCollection()`, `createSensor()`, and `createSlot()` extend the same semantics to nested data, external inputs, and integration points.
```ts
import { createState, createMemo, createEffect } from '@zeix/cause-effect'
const user = createState({ name: 'Alice', age: 30 })
const greeting = createMemo(() => `Hello ${user.get().name}`)
createEffect(() => {
console.log(`${greeting.get()}, age ${user.get().age}`)
})
user.update(value => ({ ...value, age: 31 }))
```
<Tabs items={["npm", "pnpm", "yarn", "bun"]}>
<Tab value="npm">
```bash
npm install @zeix/cause-effect
```
</Tab>
<Tab value="pnpm">
```bash
pnpm add @zeix/cause-effect
```
</Tab>
<Tab value="yarn">
```bash
yarn add @zeix/cause-effect
```
</Tab>
<Tab value="bun">
```bash
bun add @zeix/cause-effect
```
</Tab>
</Tabs>
Supported environments from `REQUIREMENTS.md`: evergreen browsers, Bun, modern Node.js with ESM, and Deno. The package itself is ESM-only and ships zero runtime dependencies.
```ts
import {
createState,
createMemo,
createTask,
createEffect,
match,
} from '@zeix/cause-effect'
const userId = createState(1)
const label = createMemo(() => `User ${userId.get()}`)
const profile = createTask(
async (_prev, abort) => {
const response = await fetch(`https://example.com/users/${userId.get()}`, {
signal: abort,
})
return response.json() as Promise<{ id: number; name: string }>
},
{ value: { id: 0, name: 'Loading...' } },
)
createEffect(() => {
match(profile, {
stale: () => console.log(`Refreshing ${label.get()}...`),
ok: user => console.log(`${label.get()}: ${user.name}`),
err: error => console.error(error.message),
})
})
userId.set(2)
```
Expected output:
```txt
Refreshing User 1...
User 1: Alice
Refreshing User 2...
User 2: Alice
```
- Fine-grained dependency tracking through `.get()` reads instead of dependency arrays.
- Unified primitives for mutable state, sync derivation, async derivation, effects, collections, and external inputs.
- Lazy watched lifecycles for sensors, collections, memos, tasks, stores, and lists.
- Stable keyed collections with item-level reactivity through `createList()` and `createCollection()`.
- Ownership utilities such as `createScope()` and `unown()` for integration layers.
- Strong TypeScript bias: non-null signal values, guard-based validation, and exported runtime type guards.
<Cards>
<Card title="Architecture" href="/docs/architecture">See how `src/graph.ts` drives propagation, cleanup, and batching.</Card>
<Card title="Core Concepts" href="/docs/state-and-derived">Learn the mental model for state, derived values, async tasks, and composite signals.</Card>
<Card title="API Reference" href="/docs/api-reference/graph-utilities">Jump to grouped API pages with signatures, options, and import paths.</Card>
</Cards>