mirror of
https://github.com/AppFlowy-IO/AppFlowy-Web.git
synced 2026-03-13 10:00:26 +08:00
refactor: grid virtualizer
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useVirtualizer } from '@tanstack/react-virtual';
|
||||
import { useCallback, useLayoutEffect, useRef } from 'react';
|
||||
import { useCallback, useLayoutEffect, useRef, useState } from 'react';
|
||||
|
||||
import { PADDING_END, useDatabaseContext } from '@/application/database-yjs';
|
||||
import { RenderColumn } from '@/components/database/components/grid/grid-column';
|
||||
@@ -11,17 +11,32 @@ const MIN_HEIGHT = 36;
|
||||
|
||||
export const PADDING_INLINE = getPlatform().isMobile ? 21 : 96;
|
||||
|
||||
const logDebug = (...args: Parameters<typeof console.debug>) => {
|
||||
if (import.meta.env.DEV) {
|
||||
console.debug(...args);
|
||||
}
|
||||
};
|
||||
|
||||
export function useGridVirtualizer({ data, columns }: { columns: RenderColumn[]; data: RenderRow[] }) {
|
||||
const { isDocumentBlock } = useDatabaseContext();
|
||||
const { isDocumentBlock, paddingStart, paddingEnd } = useDatabaseContext();
|
||||
const parentRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const parentOffsetRef = useRef(0);
|
||||
const [parentOffset, setParentOffset] = useState(0);
|
||||
|
||||
const updateParentOffset = useCallback(() => {
|
||||
if (parentRef.current) {
|
||||
parentOffsetRef.current = parentRef.current.getBoundingClientRect()?.top ?? 0;
|
||||
}
|
||||
}, []);
|
||||
if (!parentRef.current) return;
|
||||
|
||||
const nextOffset = parentRef.current.getBoundingClientRect()?.top ?? 0;
|
||||
if (nextOffset === parentOffsetRef.current) return;
|
||||
|
||||
parentOffsetRef.current = nextOffset;
|
||||
setParentOffset(nextOffset);
|
||||
logDebug('[GridVirtualizer] parent offset updated', {
|
||||
nextOffset,
|
||||
scrollMarginBeforeRender: parentOffset,
|
||||
});
|
||||
}, [parentOffset]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
updateParentOffset();
|
||||
@@ -36,7 +51,7 @@ export function useGridVirtualizer({ data, columns }: { columns: RenderColumn[];
|
||||
count: data.length,
|
||||
estimateSize: () => MIN_HEIGHT,
|
||||
overscan: 10,
|
||||
scrollMargin: parentOffsetRef.current,
|
||||
scrollMargin: parentOffset,
|
||||
getScrollElement,
|
||||
getItemKey: (index) => data[index].rowId || data[index].type,
|
||||
paddingStart: 0,
|
||||
@@ -47,20 +62,42 @@ export function useGridVirtualizer({ data, columns }: { columns: RenderColumn[];
|
||||
useLayoutEffect(() => {
|
||||
const scrollElement = getScrollElement();
|
||||
|
||||
if (!scrollElement || !isDocumentBlock) return;
|
||||
if (!scrollElement || !isDocumentBlock) {
|
||||
logDebug('[GridVirtualizer] skip observing resize', {
|
||||
hasScrollElement: !!scrollElement,
|
||||
isDocumentBlock,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
scrollElement.addEventListener('resize', updateParentOffset);
|
||||
logDebug('[GridVirtualizer] observing scroll element for resize', {
|
||||
tagName: scrollElement.tagName,
|
||||
className: scrollElement.className,
|
||||
});
|
||||
|
||||
const observer = new ResizeObserver((entries) => {
|
||||
updateParentOffset();
|
||||
logDebug('[GridVirtualizer] resize observed; recalculating offset', {
|
||||
entries: entries.map((entry) => ({
|
||||
target: entry.target instanceof HTMLElement ? entry.target.tagName : 'unknown',
|
||||
width: entry.contentRect.width,
|
||||
height: entry.contentRect.height,
|
||||
})),
|
||||
});
|
||||
});
|
||||
|
||||
observer.observe(scrollElement);
|
||||
updateParentOffset();
|
||||
|
||||
return () => {
|
||||
scrollElement.removeEventListener('resize', updateParentOffset);
|
||||
observer.disconnect();
|
||||
logDebug('[GridVirtualizer] resize observer disconnected');
|
||||
};
|
||||
}, [getScrollElement, updateParentOffset, isDocumentBlock]);
|
||||
|
||||
const getColumn = useCallback((index: number) => columns[index], [columns]);
|
||||
const getColumnWidth = useCallback((index: number) => getColumn(index).width, [getColumn]);
|
||||
|
||||
const { paddingStart, paddingEnd } = useDatabaseContext();
|
||||
|
||||
const columnVirtualizer = useVirtualizer({
|
||||
horizontal: true,
|
||||
count: columns.length,
|
||||
@@ -76,6 +113,6 @@ export function useGridVirtualizer({ data, columns }: { columns: RenderColumn[];
|
||||
parentRef,
|
||||
virtualizer,
|
||||
columnVirtualizer,
|
||||
scrollMarginTop: parentOffsetRef.current,
|
||||
scrollMarginTop: parentOffset,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user