Askr documentation
Fundamentals

Component Lifecycle Work

Attach mount, cleanup, and DOM-only work to the component lifecycle so server rendering stays deterministic.

Example

Use a resource for cancellable work whose lifetime belongs to the current component render and dependencies.

import { resource } from '@askrjs/askr/resources';

const project = resource(
  ({ signal }) => api.projects.get(projectId(), { signal }),
  [projectId]
);

Resources and tasks

`resource(fn, deps)` from `@askrjs/askr/resources` runs async work tied to a dependency list and returns `{ value, pending, error, refresh() }` — it reruns automatically whenever `deps` changes and exposes a `refresh()` you can call manually. `task(fn)` is the lower-level primitive for scheduling work as part of a component's lifecycle; the function you pass can itself return a cleanup function or a promise resolving to one, which the runtime calls when the task needs to unwind.

Events and streams

`on(target, event, handler, options?)` attaches a DOM event listener scoped to the component's lifetime — it wraps `addEventListener`/`removeEventListener` so you don't have to write the teardown yourself. `stream(source, options?)` is the equivalent primitive for values over time, but it's not the same shape as `resource` — it returns `{ value, status, pending, stale, error, restart(), close() }`, adding a `status` for connection state (`connecting`/`connected`/`reconnecting`/`closed`/`error`) and `restart()`/`close()` controls that a one-shot `resource()` call has no equivalent for.

Timers

`timer(intervalMs, fn, options?)` runs `fn` on an interval for as long as the component is mounted, and its `when` option accepts one or more activity predicates so the timer can pause itself — `routeActive(path)`, `documentVisible()`, and `windowFocused()` are the built-in predicates for "only tick while this route is showing," "only while the tab is visible," and "only while the window has focus."

Cancellation and cleanup

`resource`'s worker function receives a `{ signal }` argument — an `AbortSignal` that fires when the dependencies change or the component unmounts, so an in-flight `fetch(url, { signal })` cancels itself instead of racing a newer call. `capture(fn)` snapshots the result of a synchronous read at call time and returns a thunk to read it back later, which is the documented way to carry a consistent value into an async continuation without re-reading state that may have moved on.