From af5977691b399f315b1ea1b6f380bb7fea42bc35 Mon Sep 17 00:00:00 2001 From: sukarxn Date: Fri, 3 Apr 2026 23:23:54 +0530 Subject: [PATCH] perf: optimize ui components with react hooks memoization - toggle-group.tsx: Wrap contextValue in useMemo to prevent unnecessary re-renders - animated-tabs.tsx: Hoist constants and memoize handlers with useCallback/useMemo - LocaleContext.tsx: Wrap setLocale in useCallback and contextValue in useMemo - plate-editor.tsx: Memoize SaveShortcutPlugin and contextProviderValue, use useRef for stable references --- surfsense_web/components/editor/plate-editor.tsx | 14 ++++++++------ surfsense_web/components/ui/animated-tabs.tsx | 5 +++-- surfsense_web/components/ui/toggle-group.tsx | 5 ++++- surfsense_web/contexts/LocaleContext.tsx | 11 +++++++---- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/surfsense_web/components/editor/plate-editor.tsx b/surfsense_web/components/editor/plate-editor.tsx index 870ded55f..ed239ffa3 100644 --- a/surfsense_web/components/editor/plate-editor.tsx +++ b/surfsense_web/components/editor/plate-editor.tsx @@ -158,14 +158,16 @@ export function PlateEditor({ // When not forced read-only, the user can toggle between editing/viewing. const canToggleMode = !readOnly; + const contextProviderValue = useMemo(()=> ({ + onSave, + hasUnsavedChanges, + isSaving, + canToggleMode, + }), [onSave, hasUnsavedChanges, isSaving, canToggleMode]); + return ( ({ activeValue, onValueChange: handleValueChange }), [activeValue, handleValueChange]); return ( - +
{children}
diff --git a/surfsense_web/components/ui/toggle-group.tsx b/surfsense_web/components/ui/toggle-group.tsx index 6740fade0..860fa7a52 100644 --- a/surfsense_web/components/ui/toggle-group.tsx +++ b/surfsense_web/components/ui/toggle-group.tsx @@ -5,6 +5,7 @@ import type { VariantProps } from "class-variance-authority"; import * as React from "react"; import { toggleVariants } from "@/components/ui/toggle"; import { cn } from "@/lib/utils"; +import { useMemo } from "react"; const ToggleGroupContext = React.createContext< VariantProps & { @@ -27,6 +28,8 @@ function ToggleGroup({ VariantProps & { spacing?: number; }) { + const contextValue = useMemo(() => ({variant, size, spacing }), [variant, size, spacing]); + return ( - + {children} diff --git a/surfsense_web/contexts/LocaleContext.tsx b/surfsense_web/contexts/LocaleContext.tsx index 405fa4a50..e67e9c2a5 100644 --- a/surfsense_web/contexts/LocaleContext.tsx +++ b/surfsense_web/contexts/LocaleContext.tsx @@ -1,12 +1,13 @@ "use client"; import type React from "react"; -import { createContext, useContext, useEffect, useState } from "react"; +import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react"; import enMessages from "../messages/en.json"; import esMessages from "../messages/es.json"; import hiMessages from "../messages/hi.json"; import ptMessages from "../messages/pt.json"; import zhMessages from "../messages/zh.json"; +import { set } from "zod"; type Locale = "en" | "es" | "pt" | "hi" | "zh"; @@ -49,14 +50,14 @@ export function LocaleProvider({ children }: { children: React.ReactNode }) { }, []); // Update locale and persist to localStorage - const setLocale = (newLocale: Locale) => { + const setLocale = useCallback((newLocale: Locale) => { setLocaleState(newLocale); if (typeof window !== "undefined") { localStorage.setItem(LOCALE_STORAGE_KEY, newLocale); // Update HTML lang attribute document.documentElement.lang = newLocale; } - }; + }, []); // Set HTML lang attribute when locale changes useEffect(() => { @@ -65,8 +66,10 @@ export function LocaleProvider({ children }: { children: React.ReactNode }) { } }, [locale, mounted]); + const contextValue = useMemo(() => ({ locale, messages, setLocale }), [locale, messages, setLocale]); + return ( - + {children} );