useOfflineFirst
Reactive offline-first data binding powered by Legend-State’s sync engine.
Combines remote sync with local persistence and automatic retry. Data is available immediately from local cache, then updated from the remote source. Failed remote operations are persisted locally and retried automatically.
persistloading...
remotesyncing...
count0
import { import useOfflineFirst
useOfflineFirst } from "@usels/web";import { class ObservablePersistLocalStorage
ObservablePersistLocalStorage } from "@legendapp/state/persist-plugins/local-storage";
interface interface Settings
Settings { Settings.theme: string
theme: string; Settings.language: string
language: string;}
function function Component(): any
Component() { const { const data$: any
data$, const isLoaded$: any
isLoaded$, const isPersistLoaded$: any
isPersistLoaded$, const refetch: any
refetch } = import useOfflineFirst
useOfflineFirst<interface Settings
Settings>({ get: () => any
get: () => any
fetch("/api/settings").any
then((r: any
r) => r: any
r.any
json()), set: ({ value }: { value: any;}) => any
set: ({ value: any
value }) => any
fetch("/api/settings", { method: string
method: "PUT", body: any
body: any
JSON.any
stringify(value: any
value), }), persistKey: string
persistKey: "settings", persistPlugin: typeof ObservablePersistLocalStorage
persistPlugin: class ObservablePersistLocalStorage
ObservablePersistLocalStorage, initial: { theme: string; language: string;}
initial: { theme: string
theme: "light", language: string
language: "en" }, });
return ( <any
div> {const isPersistLoaded$: any
isPersistLoaded$.any
get() ? ( <> <any
span>{const isLoaded$: any
isLoaded$.any
get() ? "synced" : "from cache"}</any
span> <any
span>{const data$: any
data$.any
theme.any
get()}</any
span> <any
button onClick: () => any
onClick={() => const data$: any
data$.any
theme.any
set("dark")}>Dark mode</any
button> <any
button onClick: any
onClick={const refetch: any
refetch}>Sync now</any
button> </> ) : ( <any
div>Loading cache...</any
div> )} </any
div> );}Custom retry
Section titled “Custom retry”import { import useOfflineFirst
useOfflineFirst } from "@usels/web";import { class ObservablePersistLocalStorage
ObservablePersistLocalStorage } from "@legendapp/state/persist-plugins/local-storage";
function function Component(): void
Component() { const { const data$: any
data$, const clearPersist: any
clearPersist } = import useOfflineFirst
useOfflineFirst<string[]>({ get: () => any
get: () => any
fetch("/api/items").any
then((r: any
r) => r: any
r.any
json()), persistKey: string
persistKey: "items", persistPlugin: typeof ObservablePersistLocalStorage
persistPlugin: class ObservablePersistLocalStorage
ObservablePersistLocalStorage, initial: {}
initial: [], retry: { infinite: boolean; backoff: string; maxDelay: number;}
retry: { infinite: boolean
infinite: false, backoff: string
backoff: "constant", maxDelay: number
maxDelay: 5000, }, });}Type Declarations
Section titled “Type Declarations”export interface UseOfflineFirstOptions<T> { get: () => Promise<T> | T; set?: (params: { value: T; changes: object[]; }) => Promise<void> | void; initial?: T; persistKey: string; persistPlugin: PersistOptions["plugin"]; mode?: "set" | "assign" | "merge" | "append" | "prepend"; debounceSet?: number; transform?: { load?: (value: any) => T; save?: (value: T) => any; }; retry?: { infinite?: boolean; backoff?: "constant" | "exponential"; maxDelay?: number; };}export interface UseOfflineFirstReturn<T> { data$: Observable<T>; isLoaded$: ReadonlyObservable<boolean>; isFetching$: ReadonlyObservable<boolean>; isPersistLoaded$: ReadonlyObservable<boolean>; error$: ReadonlyObservable<Error | undefined>; lastSync$: ReadonlyObservable<number | undefined>; refetch: () => void; clearPersist: () => void;}export declare function useOfflineFirst<T>(options: UseOfflineFirstOptions<T>): UseOfflineFirstReturn<T>;Source
Section titled “Source”Contributors
Section titled “Contributors”- tigerwest
Changelog
Section titled “Changelog”a7392ab2026-03-06 - feat(core,browser): add sync strategy hooks (tigerwest)