From 00c740de80b14453e5c3708810c609a717c8046f Mon Sep 17 00:00:00 2001 From: kovakmedya Date: Fri, 8 May 2026 17:33:43 +0300 Subject: [PATCH] fix: remove Appwrite sync effects that caused mount-loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PrefsInitializer calls setTheme + updateConfig on mount. ThemeCustomizer was watching these with skip-first-mount effects — but after PrefsInitializer changed the values, the effects fired and called saveThemePrefsAction (server action). Next.js server actions revalidate the router cache, triggering a soft remount, resetting applied.current in PrefsInitializer, causing another save → infinite loop / flicker. Fix: dark/light and sidebar config no longer call saveThemePrefsAction from reactive effects. Sidebar saves localStorage only. Color theme / tweakcn / radius still call saveThemePrefsAction from explicit click handlers (no mount trigger, no loop). --- src/components/theme-customizer/index.tsx | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/components/theme-customizer/index.tsx b/src/components/theme-customizer/index.tsx index 054cb84..519f20a 100644 --- a/src/components/theme-customizer/index.tsx +++ b/src/components/theme-customizer/index.tsx @@ -45,14 +45,9 @@ export function ThemeCustomizer({ open, onOpenChange, initialPrefs }: ThemeCusto const [importModalOpen, setImportModalOpen] = React.useState(false) const [importedTheme, setImportedTheme] = React.useState(null) - // Save dark/light mode to Appwrite when it changes (skip first mount) - const themeMountRef = React.useRef(false) - React.useEffect(() => { - if (!themeMountRef.current) { themeMountRef.current = true; return } - void saveThemePrefsAction({ theme }) - }, [theme]) - - // Save sidebar config to localStorage + Appwrite when it changes (skip first mount) + // Sidebar config → sadece localStorage (Appwrite tetiklemesi döngüye yol açıyordu: + // PrefsInitializer mount'ta updateConfig çağırıyor → bu effect server action tetikliyor + // → Next.js router cache revalidation → remount → döngü) const sidebarMountRef = React.useRef(false) React.useEffect(() => { if (!sidebarMountRef.current) { sidebarMountRef.current = true; return } @@ -61,11 +56,6 @@ export function ThemeCustomizer({ open, onOpenChange, initialPrefs }: ThemeCusto sidebarCollapsible: sidebarConfig.collapsible, sidebarSide: sidebarConfig.side, }) - void saveThemePrefsAction({ - sidebarVariant: sidebarConfig.variant, - sidebarCollapsible: sidebarConfig.collapsible, - sidebarSide: sidebarConfig.side, - }) }, [sidebarConfig.variant, sidebarConfig.collapsible, sidebarConfig.side]) const handleReset = () => { @@ -78,7 +68,7 @@ export function ThemeCustomizer({ open, onOpenChange, initialPrefs }: ThemeCusto applyRadius("0.5rem") updateSidebarConfig({ variant: "inset", collapsible: "offcanvas", side: "left" }) saveLocalThemePrefs({ colorTheme: "default", tweakcnTheme: "", radius: "0.5rem", sidebarVariant: "inset", sidebarCollapsible: "offcanvas", sidebarSide: "left" }) - void saveThemePrefsAction({ colorTheme: "default", tweakcnTheme: "", radius: "0.5rem" }) + void saveThemePrefsAction({ colorTheme: "default", tweakcnTheme: "", radius: "0.5rem", sidebarVariant: "inset", sidebarCollapsible: "offcanvas", sidebarSide: "left" }) } const handleImport = (themeData: ImportedTheme) => {