fix(infra): memory leak (#9013)

This commit is contained in:
EYHN
2024-12-16 16:55:49 +00:00
parent 55f1cc4b1e
commit b36b398957
30 changed files with 399 additions and 135 deletions

View File

@@ -1,4 +1,4 @@
import { IconButton } from '@affine/component';
import { IconButton, observeIntersection, Skeleton } from '@affine/component';
import { useCatchEventCallback } from '@affine/core/components/hooks/use-catch-event-hook';
import { PagePreview } from '@affine/core/components/page-list/page-content-preview';
import { IsFavoriteIcon } from '@affine/core/components/pure/icons';
@@ -10,9 +10,16 @@ import {
} from '@affine/core/modules/workbench';
import { useI18n } from '@affine/i18n';
import type { DocMeta } from '@blocksuite/affine/store';
import { useLiveData, useService, WorkspaceService } from '@toeverything/infra';
import { useLiveData, useService } from '@toeverything/infra';
import clsx from 'clsx';
import { forwardRef, type ReactNode, useMemo } from 'react';
import {
forwardRef,
type ReactNode,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import * as styles from './styles.css';
import { DocCardTags } from './tag';
@@ -38,11 +45,11 @@ export interface DocCardProps extends Omit<WorkbenchLinkProps, 'to'> {
export const DocCard = forwardRef<HTMLAnchorElement, DocCardProps>(
function DocCard(
{ showTags = true, meta, className, autoHeightById, ...attrs },
ref
outerRef
) {
const containerRef = useRef<HTMLAnchorElement | null>(null);
const t = useI18n();
const favAdapter = useService(CompatibleFavoriteItemsAdapter);
const workspace = useService(WorkspaceService).workspace;
const docDisplayService = useService(DocDisplayMetaService);
const titleInfo = useLiveData(docDisplayService.title$(meta.id));
const title =
@@ -64,13 +71,35 @@ export const DocCard = forwardRef<HTMLAnchorElement, DocCardProps>(
return { height: `${rows * 18}px` };
}, [autoHeightById, meta.id]);
const [visible, setVisible] = useState(false);
useEffect(() => {
if (!containerRef.current) return;
const dispose = observeIntersection(containerRef.current, entry => {
setVisible(entry.isIntersecting);
});
return () => {
dispose();
};
}, []);
return (
<WorkbenchLink
to={`/${meta.id}`}
ref={ref}
ref={ref => {
containerRef.current = ref;
if (typeof outerRef === 'function') {
outerRef(ref);
} else if (outerRef) {
outerRef.current = ref;
}
}}
className={clsx(styles.card, className)}
data-testid="doc-card"
data-doc-id={meta.id}
data-visible={visible}
{...attrs}
>
<header className={styles.head} data-testid="doc-card-header">
@@ -83,11 +112,18 @@ export const DocCard = forwardRef<HTMLAnchorElement, DocCardProps>(
/>
</header>
<main className={styles.content} style={contentStyle}>
<PagePreview
docCollection={workspace.docCollection}
pageId={meta.id}
emptyFallback={<div className={styles.contentEmpty}>Empty</div>}
/>
{visible && (
<PagePreview
fallback={
<>
<Skeleton />
<Skeleton width={'60%'} />
</>
}
pageId={meta.id}
emptyFallback={<div className={styles.contentEmpty}>Empty</div>}
/>
)}
</main>
{showTags ? <DocCardTags docId={meta.id} rows={2} /> : null}
</WorkbenchLink>