DataFn
Client

Framework Adapters

Connect DataFn to your UI framework with thin adapter packages.

Overview

DataFn's core client is framework-agnostic. The reactive primitive DatafnSignal<T> provides subscribe(), get(), and lifecycle methods that work in any JavaScript environment.

Framework adapters are thin packages that convert a DatafnSignal<T> into the native reactive primitive of a specific UI framework — a Svelte readable store, a React hook, a Vue composable, and so on.

Why Adapter Packages?

Rather than bundling all framework integrations into @datafn/client, each framework gets its own lightweight package. This keeps bundle sizes small, avoids peer dependency conflicts, and lets you install only what you need.

Available Adapters

PackageFrameworkStatusConverts Signal To
@datafn/svelteSvelte 3/4AvailableReadable store
@datafn/reactReact 18+PlannedHook (useDatafnSignal)
@datafn/vueVue 3PlannedComposable (useDatafnSignal)
@datafn/solidSolid.jsPlannedSolid reactive signal
@datafn/angularAngular 16+PlannedObservable / Angular Signal

@datafn/svelte

Installation

npm install @datafn/svelte

Basic Usage

Convert any DatafnSignal<T> to a Svelte readable store with toSvelteStore:

import { toSvelteStore } from "@datafn/svelte";

const todosStore = toSvelteStore(
  client.todos.signal({ sort: ["-createdAt"] })
);

Template Usage

The store provides data, loading, error, refreshing, and nextCursor properties:

{#if $todosStore.loading}
  <p>Loading...</p>
{:else if $todosStore.error}
  <p>Error: {$todosStore.error.message}</p>
{:else}
  {#each $todosStore.data ?? [] as todo}
    <p>{todo.title}</p>
  {/each}
{/if}

State Properties

PropertyTypeDescription
dataTThe current query result.
loadingbooleantrue during the initial fetch before any data is available.
errorDatafnError | nullNon-null if the last fetch failed.
refreshingbooleantrue when re-fetching after a mutation (data is still available).
nextCursorstring | nullCursor for loading the next page, or null if no more pages.

Lifecycle

Signals from createDatafnClient are lifecycle-aware via LiveSignals — they survive switchContext() and rebind automatically. No factory pattern or clientRef is needed. Simply pass the signal to toSvelteStore and it works across context switches.

Composing with Svelte derived

You can compose DataFn stores with Svelte's derived to create computed values:

import { derived } from "svelte/store";

const completedCount = derived(todosStore, ($s) =>
  ($s.data ?? []).filter((t) => t.completed).length
);

Factory Overload

An additional factory-based overload is also available:

toSvelteStore(clientRef, (client) => client.todos.signal({ ... }));

Use the direct signal form when you already have a stable signal instance. Use the factory overload when signal creation depends on a client reference that can change.


The Adapter Pattern

Every framework adapter follows the same three-step pattern:

  1. Subscribe to the DatafnSignal<T> via signal.subscribe().
  2. Emit updates to the framework's reactivity system (store set, hook state update, ref assignment, etc.).
  3. Clean up the subscription when the component unmounts or the store is destroyed.

This pattern is simple enough that community adapters for any framework can be built with minimal code.


Future Framework Packages

@datafn/react (Planned)

A useDatafnSignal hook that returns reactive state:

// Planned API (not yet available)
import { useDatafnSignal } from "@datafn/react";

function TodoList() {
  const { data: todos, loading } = useDatafnSignal(
    client.todos.signal({ sort: ["-createdAt"] })
  );
  if (loading) return <p>Loading...</p>;
  return todos.map(t => <p key={t.id}>{t.title}</p>);
}

@datafn/vue (Planned)

A useDatafnSignal composable that returns reactive refs:

// Planned API (not yet available)
import { useDatafnSignal } from "@datafn/vue";

const { data: todos, loading } = useDatafnSignal(
  client.todos.signal({ sort: ["-createdAt"] })
);

@datafn/solid (Planned)

Wraps DatafnSignal<T> into Solid's fine-grained reactive system.

@datafn/angular (Planned)

Wraps DatafnSignal<T> into an RxJS Observable or Angular Signal.