Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/components/icon/icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ export class EuiIconClass extends PureComponent<
style,
...rest
} = this.props;
console.log('::render');

const { isLoading, neededLoading, iconTitle } = this.state;
const isLoaded = !isLoading && neededLoading;
Expand Down
18 changes: 18 additions & 0 deletions src/services/theme/hooks.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { testCustomHook } from '../../test/internal';
import { useEuiTheme } from './hooks';

describe('useEuiTheme', () => {
it('consecutive calls return a stable object', () => {
const hookResult = testCustomHook(useEuiTheme);
hookResult.updateHookArgs({});
expect(hookResult.return).toBe(hookResult.getUpdatedState());
});
});
31 changes: 13 additions & 18 deletions src/services/theme/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* Side Public License, v 1.
*/

import React, { forwardRef, useContext } from 'react';
import React, { forwardRef, useContext, useMemo } from 'react';

import {
EuiThemeContext,
Expand All @@ -30,11 +30,16 @@ export const useEuiTheme = <T extends {} = {}>(): UseEuiTheme<T> => {
const colorMode = useContext(EuiColorModeContext);
const modifications = useContext(EuiModificationsContext);

return {
euiTheme: theme as EuiThemeComputed<T>,
colorMode,
modifications: modifications as EuiThemeModifications<T>,
};
const assembledTheme = useMemo(
() => ({
euiTheme: theme as EuiThemeComputed<T>,
colorMode,
modifications: modifications as EuiThemeModifications<T>,
}),
[theme, colorMode, modifications]
);

return assembledTheme;
};

export interface WithEuiThemeProps<P = {}> {
Expand All @@ -51,18 +56,8 @@ export const withEuiTheme = <T extends {} = {}, U extends {} = {}>(
props: Omit<T, keyof WithEuiThemeProps<U>>,
ref: React.Ref<Omit<T, keyof WithEuiThemeProps<U>>>
) => {
const { euiTheme, colorMode, modifications } = useEuiTheme<U>();
return (
<Component
theme={{
euiTheme,
colorMode,
modifications,
}}
Comment on lines -57 to -61
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah good catch that this creates a new object on every render 🙇‍♂️

ref={ref}
{...(props as T)}
/>
);
const theme = useEuiTheme<U>();
return <Component theme={theme} ref={ref} {...(props as T)} />;
};

const WithEuiTheme = forwardRef(Render);
Expand Down
3 changes: 3 additions & 0 deletions upcoming_changelogs/6165.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**Bug fixes**

- Added memoization to `useEuiTheme`'s return value, supporting React's shallow prop comparison optimizations