Reactivity unstable
Process-local invalidation for connecting writes to dependent reads.
This module does not cache values itself. It lets callers register handlers for keys, invalidate those keys, wrap successful mutations so they invalidate keys, and expose effects as queues or streams that rerun when matching keys change. The service can also batch invalidations so handlers run after the batch completes.
Accessors
invalidate
unstableInvalidates the supplied keys through the Reactivity service.
Details
Registered queries for matching keys are rerun immediately, or collected until the enclosing reactivity batch completes.
Signature
declare function invalidate(keys: readonly Array<unknown> | ReadonlyRecord<string, readonly Array<unknown>>): Effect<void, never, Reactivity>Wraps an effect so the supplied keys are invalidated after the effect succeeds.
Gotchas
If the effect fails, the keys are not invalidated.
Signature
declare const mutation: { (keys: readonly Array<unknown> | ReadonlyRecord<string, readonly Array<unknown>>): <A, E, R>(effect: Effect<A, E, R>) => Effect<A, E, Reactivity | R>; <A, E, R>(effect: Effect<A, E, R>, keys: readonly Array<unknown> | ReadonlyRecord<string, readonly Array<unknown>>): Effect<A, E, Reactivity | R>;}Runs an effect as a query tied to the supplied invalidation keys.
Details
The returned queue receives the initial result and each later result after the keys are invalidated. The registration is removed when the current scope closes.
Signature
declare const query: { (keys: readonly Array<unknown> | ReadonlyRecord<string, readonly Array<unknown>>): <A, E, R>(effect: Effect<A, E, R>) => Effect<Dequeue<A, E>, never, Scope | Reactivity | R>; <A, E, R>(effect: Effect<A, E, R>, keys: readonly Array<unknown> | ReadonlyRecord<string, readonly Array<unknown>>): Effect<Dequeue<A, E>, never, Scope | Reactivity | R>;}Runs an effect as a stream of query results tied to the supplied invalidation keys.
Details
The effect runs initially and reruns whenever the keys are invalidated.
Signature
declare const stream: { (keys: readonly Array<unknown> | ReadonlyRecord<string, readonly Array<unknown>>): <A, E, R>(effect: Effect<A, E, R>) => Stream<A, E, Reactivity | Exclude<R, Scope>>; <A, E, R>(effect: Effect<A, E, R>, keys: readonly Array<unknown> | ReadonlyRecord<string, readonly Array<unknown>>): Stream<A, E, Reactivity | Exclude<R, Scope>>;}Constructors
Layers
Models
Registry of reactivity keys and the ID type each key accepts.
Details
The registry is empty by default, and every key name and ID is accepted.
Once an application declares keys through module augmentation, the public
reactivity APIs (Reactivity.mutation, Reactivity.query,
Reactivity.stream, Reactivity.invalidate, Atom, AtomHttpApi,
AtomRpc, SqlClient.reactive and EventLog.groupReactivity) only accept
declared key names, and record IDs must match the declared ID type. Declare
a key as never if it is only used in array form.
Gotchas
Only applications should augment this interface, never libraries. The augmentation applies to the whole program, so a library declaring keys would switch every consumer to strict keys.
Methods on the Reactivity service still accept any key, for code that only
knows its keys at runtime.
Signature
interface Keys {}Example Declaring reactivity keys
import { Effect } from "effect"import { Reactivity } from "effect/reactivity"
declare module "effect/reactivity/Reactivity" { interface Keys { readonly users: number readonly events: never }}
// Invalidates the `users` query with ID 1 and every `events` queryconst program = Effect.succeed("saved").pipe( Reactivity.mutation({ users: [1] }), Effect.andThen(Reactivity.invalidate(["events"])))Keys accepted by the public reactivity APIs.
Details
With no keys declared in Keys, any array of keys or record of key IDs is accepted. Once keys are declared, only declared key names and their ID types are accepted.
Signature
type KeysInput = [keyof Keys] extends [never] ? ReadonlyArray<unknown> | ReadonlyRecord<string, ReadonlyArray<unknown>> : ReadonlyArray<keyof Keys> | { [K in keyof Keys]: ReadonlyArray<Keys[K]> }Registers handlers and reruns queries when their keys are invalidated.
Signature
interface Reactivity { readonly "~effect/reactivity/Reactivity": "~effect/reactivity/Reactivity"; readonly invalidate: (keys: readonly Array<unknown> | ReadonlyRecord<string, readonly Array<unknown>>) => Effect<void>; readonly invalidateUnsafe: (keys: readonly Array<unknown> | ReadonlyRecord<string, readonly Array<unknown>>) => void; readonly mutation: <A, E, R>(keys: readonly Array<unknown> | ReadonlyRecord<string, readonly Array<unknown>>, effect: Effect<A, E, R>) => Effect<A, E, R>; readonly query: <A, E, R>(keys: readonly Array<unknown> | ReadonlyRecord<string, readonly Array<unknown>>, effect: Effect<A, E, R>) => Effect<Dequeue<A, E>, never, Scope | R>; readonly registerUnsafe: (keys: readonly Array<unknown> | ReadonlyRecord<string, readonly Array<unknown>>, handler: () => void) => () => void; readonly stream: <A, E, R>(keys: readonly Array<unknown> | ReadonlyRecord<string, readonly Array<unknown>>, effect: Effect<A, E, R>) => Stream<A, E, Exclude<R, Scope>>; readonly withBatch: <A, E, R>(effect: Effect<A, E, R>) => Effect<A, E, R>;}Services
Reactivity
unstableService key for reactive invalidation.
Signature
declare const Reactivity: Service<Reactivity, Reactivity>