From 909cbf7df18a5fdfa3f04fc1ee269adffbbdfc23 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 16 Jul 2026 16:18:46 +0000 Subject: [PATCH] Prevent unrelated client settings rerenders Co-authored-by: Julius Marminge --- apps/web/package.json | 2 ++ apps/web/src/hooks/useSettings.ts | 15 +++++++++++++-- pnpm-lock.yaml | 11 +++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index 5a1579a478b..70dca2c0638 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -46,6 +46,7 @@ "remark-breaks": "^4.0.0", "remark-gfm": "^4.0.1", "tailwind-merge": "^3.4.0", + "use-sync-external-store": "^1.6.0", "zustand": "^5.0.11" }, "devDependencies": { @@ -57,6 +58,7 @@ "@types/babel__core": "^7.20.5", "@types/react": "~19.2.14", "@types/react-dom": "~19.2.3", + "@types/use-sync-external-store": "^1.5.0", "@vercel/config": "^0.3.0", "@vitejs/plugin-react": "^6.0.0", "babel-plugin-react-compiler": "1.0.0", diff --git a/apps/web/src/hooks/useSettings.ts b/apps/web/src/hooks/useSettings.ts index 514484d896a..bee4c1871c6 100644 --- a/apps/web/src/hooks/useSettings.ts +++ b/apps/web/src/hooks/useSettings.ts @@ -29,6 +29,8 @@ import * as Struct from "effect/Struct"; import { primaryServerSettingsAtom, serverEnvironment } from "~/state/server"; import { usePrimaryEnvironment } from "~/state/environments"; import { useAtomCommand } from "~/state/use-atom-command"; +import { useSyncExternalStoreWithSelector } from "use-sync-external-store/with-selector"; +import { shallow } from "zustand/shallow"; const CLIENT_SETTINGS_PERSISTENCE_ERROR_SCOPE = "[CLIENT_SETTINGS]"; @@ -55,6 +57,10 @@ function getClientSettingsSnapshot(): ClientSettings { return clientSettingsSnapshot; } +function selectClientSettings(settings: ClientSettings): ClientSettings { + return settings; +} + function replaceClientSettingsSnapshot(settings: ClientSettings): void { clientSettingsSnapshot = settings; emitClientSettingsChange(); @@ -214,8 +220,13 @@ function useMergedSettings( export function useClientSettings( selector?: (settings: ClientSettings) => T, ): T { - const settings = useClientSettingsValue(); - return useMemo(() => (selector ? selector(settings) : (settings as T)), [selector, settings]); + return useSyncExternalStoreWithSelector( + subscribeClientSettings, + getClientSettingsSnapshot, + () => DEFAULT_CLIENT_SETTINGS, + selector ?? (selectClientSettings as (settings: ClientSettings) => T), + selector ? shallow : Object.is, + ); } /** Read current settings for one environment, merged with client-local preferences. */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5c50f4a98de..ec9fd6363fb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -607,6 +607,9 @@ importers: tailwind-merge: specifier: ^3.4.0 version: 3.6.0 + use-sync-external-store: + specifier: ^1.6.0 + version: 1.6.0(react@19.2.6) zustand: specifier: ^5.0.11 version: 5.0.14(@types/react@19.2.16)(react@19.2.6)(use-sync-external-store@1.6.0(react@19.2.6)) @@ -635,6 +638,9 @@ importers: '@types/react-dom': specifier: ~19.2.3 version: 19.2.3(@types/react@19.2.16) + '@types/use-sync-external-store': + specifier: ^1.5.0 + version: 1.5.0 '@vercel/config': specifier: ^0.3.0 version: 0.3.0 @@ -4921,6 +4927,9 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/use-sync-external-store@1.5.0': + resolution: {integrity: sha512-5dyB8nLC/qogMrlCizZnYWQTA4lnb/v+It+sqNl5YnSRAPMlIqY/X0Xn+gZw8vOL+TgTTr28VEbn3uf8fUtAkw==} + '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} @@ -14947,6 +14956,8 @@ snapshots: '@types/unist@3.0.3': {} + '@types/use-sync-external-store@1.5.0': {} + '@types/ws@8.18.1': dependencies: '@types/node': 24.12.4