Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Emotion] Create hook utility for memoizing component styles per-theme #7529

Merged
merged 9 commits into from
Feb 15, 2024
Prev Previous commit
Next Next commit
[PR feedback] Switch from Map to WeakMap
- to allow browser GC / avoid possible edge cases with massive RAM usage
  • Loading branch information
cee-chen committed Feb 15, 2024
commit 875dd010b835ecf04f19360d809ffd3c27df28de
13 changes: 8 additions & 5 deletions src/services/theme/style_memoization.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ import type { SerializedStyles, CSSObject } from '@emotion/react';
import { useUpdateEffect } from '../hooks';
import { useEuiTheme, UseEuiTheme } from './hooks';

type Styles = SerializedStyles | CSSObject | string | null; // Is this too restrictive?
type Styles = SerializedStyles | CSSObject | string | null;
type StylesMaps = Record<string, Styles | Record<string, Styles>>;
type MemoizedStylesMap = Map<Function, StylesMaps>;
// NOTE: We're specifically using a WeakMap instead of a Map in order to allow
// unmounted components to have their styles garbage-collected by the browser
// @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap
type MemoizedStylesMap = WeakMap<Function, StylesMaps>;

export const EuiThemeMemoizedStylesContext = createContext<MemoizedStylesMap>(
new Map()
new WeakMap()
);

export const EuiMemoizedStylesProvider: FunctionComponent<
Expand All @@ -33,13 +36,13 @@ export const EuiMemoizedStylesProvider: FunctionComponent<
// Note: we *should not* use `useMemo` instead of `useState` here, as useMemo is not guaranteed
// and its cache can get thrown away by React (https://react.dev/reference/react/useMemo#caveats)
const [componentStyles, rerenderStyles] = useState<MemoizedStylesMap>(
new Map()
new WeakMap()
);

// On theme update, wipe the map, which causes the below hook to recompute all styles
const { euiTheme } = useEuiTheme();
useUpdateEffect(() => {
rerenderStyles(new Map());
rerenderStyles(new WeakMap());
}, [euiTheme]);

return (
Expand Down