From 5b6d8fb7a8e67820254ba47361a303b2a9775d3e Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Wed, 28 Feb 2024 12:52:24 +0000 Subject: [PATCH] Added lazy-loading to comments (#19769) closes ENG-678 The comments block is typically shown at the bottom of a post so it doesn't make sense to eagerly fetch comments from the API when we don't know if the comments block will even be viewed. By lazy-loading the data only when the comments block comes into view we can reduce both data usage for visitors and load on the site. - uses IntersectionObserver API to delay comments app initialisation until the comments block has scrolled into view - updated all iframe-related components to forward a `ref` so we can use the ` ); -}; +}); type ResizableFrameProps = FrameProps & { style: React.CSSProperties, @@ -39,7 +39,7 @@ type ResizableFrameProps = FrameProps & { /** * This iframe has the same height as it contents and mimics a shadow DOM component */ -const ResizableFrame: React.FC = ({children, style, title}) => { +const ResizableFrame = React.forwardRef>(function ResizableFrame({children, style, title}, ref: React.ForwardedRef) { const [iframeStyle, setIframeStyle] = useState(style); const onResize = useCallback((iframeRoot) => { setIframeStyle((current) => { @@ -51,23 +51,25 @@ const ResizableFrame: React.FC = ({children, style, title}) }, []); return ( - + {children} ); -}; +}); -export const CommentsFrame: React.FC = ({children}) => { +type CommentsFrameProps = Record; + +export const CommentsFrame = React.forwardRef>(function CommentsFrame({children}, ref: React.ForwardedRef) { const style = { width: '100%', height: '400px' }; return ( - + {children} ); -}; +}); type PopupFrameProps = FrameProps & { title: string diff --git a/apps/comments-ui/src/components/IFrame.tsx b/apps/comments-ui/src/components/IFrame.tsx index 3dc5e8de0c..611a7d03e5 100644 --- a/apps/comments-ui/src/components/IFrame.tsx +++ b/apps/comments-ui/src/components/IFrame.tsx @@ -1,10 +1,10 @@ -import {Component} from 'react'; +import {Component, forwardRef} from 'react'; import {createPortal} from 'react-dom'; /** * This is still a class component because it causes issues with the behaviour (DOM recreation and layout glitches) if we switch to a functional component. Feel free to refactor. */ -export default class IFrame extends Component { +class IFrame extends Component { node: any; iframeHtml: any; iframeHead: any; @@ -59,6 +59,7 @@ export default class IFrame extends Component { setNode(node: any) { this.node = node; + this.props.innerRef.current = node; } render() { @@ -71,3 +72,9 @@ export default class IFrame extends Component { ); } } + +const IFrameFC = forwardRef(function IFrameFC(props, ref) { + return