Skip to content

Memoize context provider value objects to prevent unnecessary consumer re-renders #1096

@MODSetter

Description

@MODSetter

Description

Several context providers pass fresh object literals as value, causing every consumer to re-render whenever the provider's parent re-renders — even if the actual values haven't changed.

Files to change

1. surfsense_web/components/ui/toggle-group.tsx (line 43)

<ToggleGroupContext.Provider value={{ variant, size, spacing }}>

Fix:

const contextValue = useMemo(() => ({ variant, size, spacing }), [variant, size, spacing]);
<ToggleGroupContext.Provider value={contextValue}>

2. surfsense_web/components/ui/animated-tabs.tsx (line 206)

<TabsContext.Provider value={{ activeValue, onValueChange: handleValueChange }}>

Fix: useMemo(() => ({ activeValue, onValueChange: handleValueChange }), [activeValue, handleValueChange])

3. surfsense_web/contexts/LocaleContext.tsx (line 69)

<LocaleContext.Provider value={{ locale, messages, setLocale }}>

Fix: First, wrap setLocale (line 52) in useCallback since it's recreated every render. Then useMemo the context value:

const setLocale = useCallback((newLocale: Locale) => { ... }, []);
const contextValue = useMemo(() => ({ locale, messages, setLocale }), [locale, messages, setLocale]);

4. surfsense_web/components/editor/plate-editor.tsx (lines 162-168)

<EditorSaveContext.Provider value={{ onSave, hasUnsavedChanges, isSaving, canToggleMode }}>

Fix: useMemo(() => ({ onSave, hasUnsavedChanges, isSaving, canToggleMode }), [onSave, hasUnsavedChanges, isSaving, canToggleMode])

Acceptance criteria

  • All listed context providers use useMemo for their value prop
  • Unstable callbacks (like setLocale) are wrapped in useCallback
  • All context consumers still work correctly

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions