Skip to content

Data Fetching

use-legend offers two paths for fetching and syncing remote data. Pick the one that fits your data ownership model.

  • Legend-State Sync (useRemote, useOfflineFirst) — the observable is the data, sync is a trait. You own the data model end-to-end.
  • TanStack Query (@usels/tanstack-query) — query cache owns data, observable wraps query state. For API consumption with caching, deduplication, and pagination.

Use useRemote when the observable itself is the source of truth and the server is just a backing store.

import { useRemote } from "@usels/core";
function Profile() {
const { data$, isLoaded$ } = useRemote({
get: () => fetch("/api/profile").then((res) => res.json()),
set: ({ value }) => fetch("/api/profile", { method: "PUT", body: JSON.stringify(value) }),
initial: { name: "" },
});
return isLoaded$.get()
? <input value={data$.name.get()} onChange={(e) => data$.name.set(e.target.value)} />
: <p>Loading…</p>;
}

For offline-first scenarios, useOfflineFirst adds local persistence and retry:

import { useOfflineFirst } from "@usels/core";
import { ObservablePersistLocalStorage } from "@legendapp/state/persist-plugins/local-storage";
function Profile() {
const { data$, isLoaded$ } = useOfflineFirst({
get: () => fetch("/api/profile").then((res) => res.json()),
set: ({ value }) => fetch("/api/profile", { method: "PUT", body: JSON.stringify(value) }),
initial: { name: "" },
persistKey: "profile",
persistPlugin: ObservablePersistLocalStorage,
});
// data loads from local storage first, then syncs with remote
}

Use @usels/tanstack-query when you need query caching, background refetching, pagination, or optimistic updates from TanStack Query — with observable results.

import { QueryClient, QueryClientProvider } from "@usels/tanstack-query";
import { useQuery } from "@usels/tanstack-query";
import { observable } from "@usels/core";
const queryClient = new QueryClient();
const category$ = observable("all");
function ProductList() {
const query = useQuery({
queryKey: ["products", category$],
queryFn: () => fetchProducts(category$.peek()),
});
return <p>{query.data.get()?.length ?? 0} products</p>;
}

See the TanStack Query API reference for useQuery, useMutation, useInfiniteQuery, and useQueryClient.