From 82c0a45ea0334a8ffd5747e080ca693f54921d66 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Mon, 9 Mar 2026 13:00:27 -0700 Subject: [PATCH] Use Debouncer for composer draft persistence writes - Replace manual timeout/pending-value debounce logic with `@tanstack/react-pacer` `Debouncer` - Keep `removeItem`/`flush` behavior while simplifying and standardizing persistence timing --- apps/web/src/composerDraftStore.ts | 38 +++++++++--------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/apps/web/src/composerDraftStore.ts b/apps/web/src/composerDraftStore.ts index 6be7efe464f7406c6c36d346b695f0c0a099a0ca..0369b97735940e39eaef95813fb2c023783f0f2b 100644 --- a/apps/web/src/composerDraftStore.ts +++ b/apps/web/src/composerDraftStore.ts @@ -14,6 +14,7 @@ import { DEFAULT_RUNTIME_MODE, type ChatImageAttachment, } from "./types"; +import { Debouncer } from "@tanstack/react-pacer"; import { create } from "zustand"; import { createJSONStorage, persist, type StateStorage } from "zustand/middleware"; @@ -27,41 +28,24 @@ interface DebouncedStorage extends StateStorage { } export function createDebouncedStorage(baseStorage: StateStorage): DebouncedStorage { - let timer: ReturnType | null = null; - let pendingName: string | null = null; - let pendingValue: string | null = null; + const debouncedSetItem = new Debouncer( + (name: string, value: string) => { + baseStorage.setItem(name, value); + }, + { wait: COMPOSER_PERSIST_DEBOUNCE_MS }, + ); + return { getItem: (name) => baseStorage.getItem(name), setItem: (name, value) => { - pendingName = name; - pendingValue = value; - if (timer !== null) { - clearTimeout(timer); - } - timer = setTimeout(() => { - timer = null; - pendingName = null; - pendingValue = null; - baseStorage.setItem(name, value); - }, COMPOSER_PERSIST_DEBOUNCE_MS); + debouncedSetItem.maybeExecute(name, value); }, removeItem: (name) => { - if (timer !== null) { - clearTimeout(timer); - timer = null; - pendingName = null; - pendingValue = null; - } + debouncedSetItem.cancel(); baseStorage.removeItem(name); }, flush: () => { - if (timer !== null && pendingName !== null && pendingValue !== null) { - clearTimeout(timer); - timer = null; - baseStorage.setItem(pendingName, pendingValue); - pendingName = null; - pendingValue = null; - } + debouncedSetItem.flush(); }, }; } -- 2.54.0