mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-05 12:22:45 +02:00
perf(v2): lazy collapsibles, reduce html output and build times (#5136)
* Allow collapsible to be lazy * cleanup comments * CollapsibleLazy little bug
This commit is contained in:
parent
04bcdbd3e1
commit
677e53d4db
4 changed files with 50 additions and 10 deletions
|
@ -141,7 +141,7 @@ function DocSidebarItemCategory({
|
|||
{label}
|
||||
</a>
|
||||
|
||||
<Collapsible as="ul" className="menu__list" collapsed={collapsed}>
|
||||
<Collapsible lazy as="ul" className="menu__list" collapsed={collapsed}>
|
||||
<DocSidebarItems
|
||||
items={items}
|
||||
tabIndex={collapsed ? -1 : 0}
|
||||
|
|
|
@ -209,7 +209,8 @@ function NavItemMobile({
|
|||
}}>
|
||||
{props.children ?? props.label}
|
||||
</NavLink>
|
||||
<Collapsible as="ul" className="menu__list" collapsed={collapsed}>
|
||||
|
||||
<Collapsible lazy as="ul" className="menu__list" collapsed={collapsed}>
|
||||
{items.map(({className: childItemClassName, ...childItemProps}, i) => (
|
||||
<li className="menu__list-item" key={i}>
|
||||
<NavLink
|
||||
|
|
|
@ -40,6 +40,7 @@ export default function TOCCollapsible({toc, className}: TOCCollapsibleProps) {
|
|||
</button>
|
||||
|
||||
<Collapsible
|
||||
lazy
|
||||
className={styles.tocCollapsibleContent}
|
||||
collapsed={collapsed}>
|
||||
<TOCHeadings toc={toc} />
|
||||
|
|
|
@ -15,6 +15,7 @@ import React, {
|
|||
Dispatch,
|
||||
SetStateAction,
|
||||
ReactNode,
|
||||
useLayoutEffect,
|
||||
} from 'react';
|
||||
|
||||
const DefaultAnimationEasing = 'ease-in-out';
|
||||
|
@ -158,19 +159,21 @@ function getSSRStyle(collapsed: boolean) {
|
|||
return collapsed ? CollapsedStyles : ExpandedStyles;
|
||||
}
|
||||
|
||||
export function Collapsible({
|
||||
type CollapsibleBaseProps = {
|
||||
as?: CollapsibleElementType;
|
||||
collapsed: boolean;
|
||||
children: ReactNode;
|
||||
animation?: CollapsibleAnimationConfig;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
function CollapsibleBase({
|
||||
as: As = 'div',
|
||||
collapsed,
|
||||
children,
|
||||
animation,
|
||||
className,
|
||||
}: {
|
||||
as?: CollapsibleElementType; // TODO better typing, allow any html element (keyof JSX.IntrinsicElement => not working)
|
||||
collapsed: boolean;
|
||||
children: ReactNode;
|
||||
animation?: CollapsibleAnimationConfig;
|
||||
className?: string;
|
||||
}) {
|
||||
}: CollapsibleBaseProps) {
|
||||
// any because TS is a pain for HTML element refs, see https://twitter.com/sebastienlorber/status/1412784677795110914
|
||||
const collapsibleRef = useRef<any>(null);
|
||||
|
||||
|
@ -205,3 +208,38 @@ export function Collapsible({
|
|||
</As>
|
||||
);
|
||||
}
|
||||
|
||||
function CollapsibleLazy({collapsed, ...props}: CollapsibleBaseProps) {
|
||||
const [mounted, setMounted] = useState(!collapsed);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!collapsed) {
|
||||
setMounted(true);
|
||||
}
|
||||
}, [collapsed]);
|
||||
|
||||
// lazyCollapsed updated in effect so that the first expansion transition can work
|
||||
const [lazyCollapsed, setLazyCollapsed] = useState(collapsed);
|
||||
useLayoutEffect(() => {
|
||||
if (mounted) {
|
||||
setLazyCollapsed(collapsed);
|
||||
}
|
||||
}, [mounted, collapsed]);
|
||||
|
||||
return mounted ? (
|
||||
<CollapsibleBase {...props} collapsed={lazyCollapsed} />
|
||||
) : null;
|
||||
}
|
||||
|
||||
type CollapsibleProps = CollapsibleBaseProps & {
|
||||
// Lazy allows to delay the rendering when collapsed => it will render children only after hydration, on first expansion
|
||||
// Required prop: it forces to think if content should be server-rendered or not!
|
||||
// This has perf impact on the SSR output and html file sizes
|
||||
// See https://github.com/facebook/docusaurus/issues/4753
|
||||
lazy: boolean;
|
||||
};
|
||||
|
||||
export function Collapsible({lazy, ...props}: CollapsibleProps) {
|
||||
const Comp = lazy ? CollapsibleLazy : CollapsibleBase;
|
||||
return <Comp {...props} />;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue