Skip to content

Commit

Permalink
Lazy mounting for popovers for performance
Browse files Browse the repository at this point in the history
  • Loading branch information
rushi committed May 22, 2024
1 parent 474ef2a commit 3227da1
Showing 1 changed file with 46 additions and 4 deletions.
50 changes: 46 additions & 4 deletions src/components/Popover/Popover.jsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import Tippy from "@tippyjs/react";
import clsx from "clsx";
import PropTypes from "prop-types";
import React, { Children } from "react";
import React, { Children, useState } from "react";
import { followCursor } from "tippy.js";
import "tippy.js/dist/border.css";
import "tippy.js/dist/tippy.css";
import { getChildrenByType } from "../../helpers/children";
import styles from "./Popover.module.css";
import scrollFix from "./PopoverScroll.module.css";

export const Popover = ({ className, children, skidding = 0, distance = 10, ...rest }) => {
export const Popover = ({ lazy = true, skidding = 0, distance = 10, className, children, ...rest }) => {
const content = getChildrenByType(children, Popover.Content);
const target = Children.toArray(children).filter((child) => child.type !== Popover.Content);

// See the explanation below for why we need to use lazy mounting
const TippyComponent = lazy ? LazyTippy : Tippy;

return (
<Tippy
<TippyComponent
interactive
zIndex={50}
content={content}
Expand All @@ -30,11 +33,12 @@ export const Popover = ({ className, children, skidding = 0, distance = 10, ...r
{...rest}
>
<span>{target}</span>
</Tippy>
</TippyComponent>
);
};

Popover.propTypes = {
lazy: PropTypes.bool,

Check failure on line 41 in src/components/Popover/Popover.jsx

View workflow job for this annotation

GitHub Actions / View Lint Report

src/components/Popover/Popover.jsx#L41

[react/boolean-prop-naming] Prop name (lazy) doesn't match rule (^(is|has|should)[A-Z]([A-Za-z0-9]?)+)
className: PropTypes.string,
skidding: PropTypes.number,
distance: PropTypes.number,
Expand All @@ -52,3 +56,41 @@ Content.propTypes = {
};

Popover.Content = Content;


/**

Check failure on line 61 in src/components/Popover/Popover.jsx

View workflow job for this annotation

GitHub Actions / View Lint Report

src/components/Popover/Popover.jsx#L60-L61

[prettier/prettier] Delete `⏎`
* This is to ensure lazy mounting which will not mount the content until the tippy is shown.
*
* By default, Tippy mounts your content or render elements into a container element once created,
* even if the tippy isn't mounted on the DOM. In most cases, this is fine, but in performance-sensitive scenarios
* or cases where mounting the component should fire effects only when the tippy mounted, you can lazify the component.
*
* WHY?
* In React, a component gets mounted even if the JSX is not immediately rendered on screen due to React's
* virtual DOM reconciliation process. When a component is rendered but not displayed, it still goes through
* the mounting phase where the component instance is created and its lifecycle methods are called.
* This allows React to manage the component's state, props, and perform any necessary setup tasks.
*
* This behavior is need for maintaining component state and lifecycle methods, ensuring consistency in component behavior.
*/
const LazyTippy = React.forwardRef((props, ref) => {
const [mounted, setMounted] = useState(false);

const lazyPlugin = {
fn: () => ({
onMount: () => setMounted(true),
onHidden: () => setMounted(false),
}),
};

const computedProps = { ...props };
computedProps.plugins = [lazyPlugin, ...(props.plugins || [])];

if (props.render) {
computedProps.render = (...args) => (mounted ? props.render(...args) : '');

Check failure on line 90 in src/components/Popover/Popover.jsx

View workflow job for this annotation

GitHub Actions / View Lint Report

src/components/Popover/Popover.jsx#L90

[unicorn/prevent-abbreviations] The variable `args` should be named `arguments_`. A more descriptive name will do too.

Check failure on line 90 in src/components/Popover/Popover.jsx

View workflow job for this annotation

GitHub Actions / View Lint Report

src/components/Popover/Popover.jsx#L90

[prettier/prettier] Replace `''` with `""`
} else {
computedProps.content = mounted ? props.content : '';

Check failure on line 92 in src/components/Popover/Popover.jsx

View workflow job for this annotation

GitHub Actions / View Lint Report

src/components/Popover/Popover.jsx#L92

[prettier/prettier] Replace `''` with `""`
}

return <Tippy {...computedProps} ref={ref} />;
});

0 comments on commit 3227da1

Please sign in to comment.