Skip to content

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
>
);
}
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,
},
});
}
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>;

View on GitHub

  • tigerwest
  • a7392ab 2026-03-06 - feat(core,browser): add sync strategy hooks (tigerwest)