Performance: Create separate div for portal root to limit reflow -> recalc style (#47633)

* Performance: Create separate div for portal root to limit reflow -> recalc style

* refactoring
This commit is contained in:
Torkel Ödegaard 2022-04-13 07:39:22 +02:00 committed by GitHub
parent a4381ebc91
commit 6042beab43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 20 additions and 5 deletions

View File

@ -9,9 +9,11 @@ interface Props {
}
export function Portal(props: PropsWithChildren<Props>) {
const { children, className, root: portalRoot = document.body, forwardedRef } = props;
const { children, className, root, forwardedRef } = props;
const theme = useTheme2();
const node = useRef<HTMLDivElement | null>(null);
const portalRoot = root ?? getPortalContainer();
if (!node.current) {
node.current = document.createElement('div');
if (className) {
@ -25,6 +27,7 @@ export function Portal(props: PropsWithChildren<Props>) {
if (node.current) {
portalRoot.appendChild(node.current);
}
return () => {
if (node.current) {
portalRoot.removeChild(node.current);
@ -35,7 +38,18 @@ export function Portal(props: PropsWithChildren<Props>) {
return ReactDOM.createPortal(<div ref={forwardedRef}>{children}</div>, node.current);
}
/** @internal */
export function getPortalContainer() {
return window.document.getElementById('grafana-portal-container') ?? document.body;
}
/** @internal */
export function PortalContainer() {
return <div id="grafana-portal-container" />;
}
export const RefForwardingPortal = React.forwardRef<HTMLDivElement, Props>((props, ref) => {
return <Portal {...props} forwardedRef={ref} />;
});
RefForwardingPortal.displayName = 'RefForwardingPortal';

View File

@ -6,7 +6,7 @@ export { Tooltip } from './Tooltip/Tooltip';
export { PopoverContent } from './Tooltip/types';
export { PopoverController } from './Tooltip/PopoverController';
export { Popover } from './Tooltip/Popover';
export { Portal } from './Portal/Portal';
export { Portal, getPortalContainer, PortalContainer } from './Portal/Portal';
export { CustomScrollbar, ScrollbarPosition } from './CustomScrollbar/CustomScrollbar';
export { TabbedContainer, TabConfig } from './TabbedContainer/TabbedContainer';

View File

@ -3,7 +3,7 @@ import { Router, Route, Redirect, Switch } from 'react-router-dom';
import { config, locationService, navigationLogger } from '@grafana/runtime';
import { Provider } from 'react-redux';
import { store } from 'app/store/store';
import { ErrorBoundaryAlert, GlobalStyles, ModalRoot, ModalsProvider } from '@grafana/ui';
import { ErrorBoundaryAlert, GlobalStyles, ModalRoot, ModalsProvider, PortalContainer } from '@grafana/ui';
import { GrafanaApp } from './app';
import { getAppRoutes } from 'app/routes/routes';
import { ConfigContext, ThemeProvider } from './core/utils/ConfigProvider';
@ -113,6 +113,7 @@ export class AppWrapper extends React.Component<AppWrapperProps, AppWrapperState
</div>
<LiveConnectionWarning />
<ModalRoot />
<PortalContainer />
</ModalsProvider>
</ThemeProvider>
</ConfigContext.Provider>

View File

@ -1,6 +1,6 @@
import React, { ReactElement, useEffect, useState } from 'react';
import { css, cx } from '@emotion/css';
import { Icon, IconName, Link, useTheme2 } from '@grafana/ui';
import { getPortalContainer, Icon, IconName, Link, useTheme2 } from '@grafana/ui';
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
import { MenuTriggerProps } from '@react-types/menu';
import { useMenuTriggerState } from '@react-stately/menu';
@ -182,7 +182,7 @@ export function NavBarItemMenuTrigger(props: NavBarItemMenuTriggerProps): ReactE
<div className={cx(styles.element, 'dropdown')} {...focusWithinProps} {...hoverProps}>
{element}
{state.isOpen && (
<OverlayContainer>
<OverlayContainer portalContainer={getPortalContainer()}>
<NavBarItemMenuContext.Provider
value={{
menuProps,