authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-03-09 12:28:26-07:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-03-09 14:02:29-07:00
logf5e4df5cab247021501876358fd72c7196cd96b9
treeff56ab6b3b3353eb1811356510407686849c2c47
parent1f47cc6f4e51d236421d45bafabaa3bbf2576c3f

Use Debouncer for store state persistence

- Replace manual timeout debounce logic with `@tanstack/react-pacer`'s `Debouncer` - Persist updates via `maybeExecute` to reduce localStorage write thrashing - Flush pending persistence on `beforeunload` to avoid losing recent state

1 files changed, 4 insertions(+), 18 deletions(-)

apps/web/src/store.ts+4-18
......@@ -14,6 +14,7 @@ import {
1414} from "@t3tools/shared/model";
1515import { create } from "zustand";
1616import { type ChatMessage, type Project, type Thread } from "./types";
17import { Debouncer } from "@tanstack/react-pacer";
1718
1819// ── State ────────────────────────────────────────────────────────────
1920
......@@ -86,18 +87,7 @@ function persistState(state: AppState): void {
8687 // Ignore quota/storage errors to avoid breaking chat UX.
8788 }
8889}
89
90let persistTimer: ReturnType<typeof setTimeout> | null = null;
91
92function debouncedPersistState(state: AppState): void {
93 if (persistTimer !== null) {
94 clearTimeout(persistTimer);
95 }
96 persistTimer = setTimeout(() => {
97 persistTimer = null;
98 persistState(state);
99 }, 500);
100}
90const debouncedPersistState = new Debouncer(persistState, { wait: 500 });
10191
10292// ── Pure helpers ──────────────────────────────────────────────────────
10393
......@@ -413,16 +403,12 @@ export const useStore = create<AppStore>((set) => ({
413403}));
414404
415405// Persist state changes with debouncing to avoid localStorage thrashing
416useStore.subscribe((state) => debouncedPersistState(state));
406useStore.subscribe((state) => debouncedPersistState.maybeExecute(state));
417407
418408// Flush pending writes synchronously before page unload to prevent data loss.
419409if (typeof window !== "undefined") {
420410 window.addEventListener("beforeunload", () => {
421 if (persistTimer !== null) {
422 clearTimeout(persistTimer);
423 persistTimer = null;
424 persistState(useStore.getState());
425 }
411 debouncedPersistState.flush();
426412 });
427413}
428414