Skip to content

Commit

Permalink
fix: fix LazyLoad componentDidMount dom no use error
Browse files Browse the repository at this point in the history
  • Loading branch information
chenshuai2144 committed May 20, 2023
1 parent f6f5167 commit c0635f5
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 24 deletions.
1 change: 0 additions & 1 deletion example/.dumirc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ export default defineConfig({
'dumi-theme-antd-style': path.join(__dirname, '../src'),
},
mfsu: false,
extraBabelPlugins: ['@emotion'],
styles: [
`html, body { background: transparent; }
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@
"polished": "^4",
"rc-footer": "^0.6",
"react-layout-kit": "^1",
"react-lazy-load": "^4.0.1",
"react-syntax-highlighter": "^15",
"shiki-es": "^0.2",
"use-merge-value": "^1",
Expand Down
26 changes: 4 additions & 22 deletions src/builtins/Previewer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Card } from 'antd';
import { createStyles } from 'antd-style';
import { IPreviewerProps } from 'dumi/dist/client/theme-api/types';
import Previewer from 'dumi/theme-default/builtins/Previewer';
import { rgba } from 'polished';
import { useMemo, useState } from 'react';
import LazyLoad from 'react-lazy-load';
import { useMemo } from 'react';
import DemoProvider from '../../components/DemoProvider';
import { IntersectionLoad } from '../../components/LazyLoad';

const useStyles = createStyles(({ css, token, prefixCls }) => {
return {
Expand Down Expand Up @@ -124,8 +123,6 @@ const useStyles = createStyles(({ css, token, prefixCls }) => {
export default (props: IPreviewerProps) => {
const { styles, cx, theme } = useStyles();

const [loading, setLoading] = useState(true);

const height = useMemo(() => {
if (typeof props.iframe === 'number') {
return props.iframe;
Expand All @@ -138,26 +135,11 @@ export default (props: IPreviewerProps) => {

return (
<div className={cx(styles.container, styles[props.codePlacement as 'left' | 'right' | 'top'])}>
<LazyLoad
elementType="section"
onContentVisible={() => {
setLoading(false);
}}
>
<IntersectionLoad height={height} elementType="section">
<DemoProvider inherit={props.inherit || theme.demoInheritSiteTheme}>
<Previewer {...props} />
</DemoProvider>
</LazyLoad>
{loading && (
<Card
className="loading"
loading
style={{
height,
width: '100%',
}}
/>
)}
</IntersectionLoad>
</div>
);
};
137 changes: 137 additions & 0 deletions src/components/LazyLoad/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// copy form https://github.com/loktar00/react-lazy-load/blob/master/src/LazyLoad.tsx#L2
import { Card } from 'antd';
import React, { Children, Component, createElement, ReactNode, RefObject } from 'react';
import scrollParent from './utils';

type Props = {
children: ReactNode;
className?: string;
elementType?: string;
height?: string | number;
offset?: string | number;
threshold?: number;
width?: number | string;
onContentVisible?: () => void;
};

type State = {
visible: boolean;
};

export class IntersectionLoad extends Component<Props, State> {
static defaultProps = {
elementType: 'div',
className: '',
offset: 0,
threshold: 0,
width: null,
onContentVisible: null,
height: null,
};

elementObserver: IntersectionObserver | null;

wrapper: RefObject<HTMLElement> | null;

constructor(props: Props) {
super(props);
this.elementObserver = null;
this.wrapper = React.createRef();

this.state = { visible: false };
}

componentDidMount() {
let eventNode = this.getEventNode();

if (eventNode === window) {
eventNode = document.body;
}

setTimeout(() => {
const { offset, threshold } = this.props;
const options = {
rootMargin: typeof offset === 'number' ? `${offset}px` : offset || '0px',
threshold: threshold || 0,

root: document.body,
};

this.elementObserver = new IntersectionObserver(this.lazyLoadHandler, options);

const node = this.wrapper?.current;

if (node instanceof HTMLElement) {
this.elementObserver.observe(node);
}
}, 200);
}

shouldComponentUpdate(_: Props, nextState: State) {
return nextState.visible;
}

componentWillUnmount() {
const node = this.wrapper?.current;
console.log(node);
if (node && node instanceof HTMLElement) {
this.elementObserver?.unobserve(node);
}
}

getEventNode() {
if (!this.wrapper?.current) return document.body;
return scrollParent(this.wrapper?.current);
}

lazyLoadHandler = (entries: IntersectionObserverEntry[]) => {
const { onContentVisible } = this.props;
const [entry] = entries;
const { isIntersecting } = entry;

if (isIntersecting) {
this.setState({ visible: true }, () => {
if (onContentVisible) {
onContentVisible();
}
});

// Stop observing
const node = this.wrapper?.current;
if (node && node instanceof HTMLElement) {
this.elementObserver?.unobserve(node);
}
}
};

render() {
const { children, className, height, width, elementType } = this.props;
const { visible } = this.state;

const elStyles = { width };
const elClasses = `LazyLoad${visible ? ' is-visible' : ''}${className ? ` ${className}` : ''}`;

const componentElementType = elementType || 'div';

return createElement(
componentElementType,
{
className: elClasses,
style: elStyles,
ref: this.wrapper,
},
visible ? (
Children.only(children)
) : (
<Card
className="loading"
loading
style={{
height,
width: '100%',
}}
/>
),
);
}
}
33 changes: 33 additions & 0 deletions src/components/LazyLoad/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const style = (element: HTMLElement, prop: string) =>
typeof getComputedStyle !== 'undefined'
? getComputedStyle(element, null).getPropertyValue(prop)
: element.style.getPropertyValue(prop);

const overflow = (element: HTMLElement) =>
style(element, 'overflow') + style(element, 'overflow-y') + style(element, 'overflow-x');

export default (element: HTMLElement) => {
if (!(element instanceof HTMLElement)) {
return window;
}

let parent = element;

while (parent) {
if (parent === document.body || parent === document.documentElement) {
break;
}

if (!parent.parentNode) {
break;
}

if (/(scroll|auto)/.test(overflow(parent))) {
return parent;
}

parent = parent.parentNode as HTMLDivElement;
}

return window;
};

0 comments on commit c0635f5

Please sign in to comment.