From 8b6def94f65f93767a566b7b1d954e8c0bf62ec3 Mon Sep 17 00:00:00 2001 From: hamed-musallam <35760236+hamed-musallam@users.noreply.github.com> Date: Thu, 10 Nov 2022 14:50:24 +0100 Subject: [PATCH] fix: react table virtual scroll (#1879) * fix: react table virtual scroll close #1863 --- .../elements/ReactTable/ReactTable.tsx | 96 ++++++++----------- .../ReactTable/utility/ReactTableContext.ts | 4 +- 2 files changed, 42 insertions(+), 58 deletions(-) diff --git a/src/component/elements/ReactTable/ReactTable.tsx b/src/component/elements/ReactTable/ReactTable.tsx index 46ab6ba78..8a2d2abf5 100644 --- a/src/component/elements/ReactTable/ReactTable.tsx +++ b/src/component/elements/ReactTable/ReactTable.tsx @@ -2,14 +2,13 @@ /** @jsxImportSource @emotion/react */ import { useRef, - useCallback, memo, forwardRef, useState, Ref, - useEffect, - UIEvent, CSSProperties, + WheelEvent, + useLayoutEffect, } from 'react'; import { useTable, useSortBy } from 'react-table'; import { useMeasure } from 'react-use'; @@ -41,7 +40,7 @@ interface ReactTableProps extends ClickEvent { } interface ReactTableInnerProps extends ReactTableProps { - onScroll: (event: UIEvent) => void; + onScroll: (event: WheelEvent) => void; } const styles = { @@ -84,7 +83,7 @@ const ReactTableInner = forwardRef(function ReactTableInner( } = props; const contextRef = useRef(null); - const { index: indexBoundary } = useReactTableContext(); + const virtualBoundary = useReactTableContext(); const [rowIndex, setRowIndex] = useState(); const timeoutIdRef = useRef(); const [isCounterVisible, setCounterVisibility] = useState(false); @@ -104,27 +103,17 @@ const ReactTableInner = forwardRef(function ReactTableInner( useSortBy, useRowSpan, ); - const contextMenuHandler = useCallback( - (e, row) => { - if (!checkModifierKeyActivated(e)) { - e.preventDefault(); - contextRef.current.handleContextMenu(e, row.original); - } - }, - [contextRef], - ); - - const rowsData = enableVirtualScroll - ? rows.slice(indexBoundary.start, indexBoundary.end) - : rows; + function contextMenuHandler(e, row) { + if (!checkModifierKeyActivated(e)) { + e.preventDefault(); + contextRef.current.handleContextMenu(e, row.original); + } + } - const clickHandler = useCallback( - (event, row) => { - setRowIndex(row.index); - onClick?.(event, row); - }, - [onClick], - ); + function clickHandler(event, row) { + setRowIndex(row.index); + onClick?.(event, row); + } function scrollHandler(e) { if (enableVirtualScroll) { @@ -141,6 +130,14 @@ const ReactTableInner = forwardRef(function ReactTableInner( }, 1000); } + const end = + virtualBoundary.end === rows.length - 1 + ? virtualBoundary.end + 1 + : virtualBoundary.end; + const rowsData = enableVirtualScroll + ? rows.slice(virtualBoundary.start, end) + : rows; + const index = rowsData[rowsData.length - 1]?.original[indexKey] || rowsData[rowsData.length - 1]?.index; @@ -161,7 +158,7 @@ const ReactTableInner = forwardRef(function ReactTableInner( {enableVirtualScroll && (
(null); + const visibleRowsCountRef = useRef(0); const [mRef, { height }] = useMeasure(); - const [tableVirtualConfig, setTableVirtualConfig] = - useState({ - scrollHeight: 0, - numberOfVisibleRows: 0, - index: { start: 0, end: 0 }, + const [tableVirtualBoundary, setTableVirtualBoundary] = + useState({ + start: 1, + end: 0, }); - useEffect(() => { + useLayoutEffect(() => { if (containerRef.current) { - const { scrollHeight } = containerRef.current; const header = containerRef.current.querySelectorAll('thead'); - const numberOfVisibleRows = Math.ceil( + visibleRowsCountRef.current = Math.ceil( (height - header[0].clientHeight) / approxItemHeight, ); - setTableVirtualConfig((prev) => ({ - ...prev, - scrollHeight, - numberOfVisibleRows: numberOfVisibleRows - 1, - index: { start: 0, end: numberOfVisibleRows }, - })); + setTableVirtualBoundary({ start: 0, end: visibleRowsCountRef.current }); } }, [approxItemHeight, height]); @@ -300,23 +290,17 @@ function ReactTable(props: ReactTableProps) { } function scrollHandler() { - if (containerRef.current && tableVirtualConfig) { + if (containerRef.current) { const { scrollTop } = containerRef.current; - const { numberOfVisibleRows, index } = tableVirtualConfig; const currentIndx = Math.ceil(scrollTop / approxItemHeight); - const start = findStartIndex(currentIndx, numberOfVisibleRows); - if (currentIndx !== index.start) { - const end = findEndIndex(currentIndx, numberOfVisibleRows); - setTableVirtualConfig({ - ...tableVirtualConfig, - index: { start, end: end + 1 }, - }); - } + const start = findStartIndex(currentIndx, visibleRowsCountRef.current); + const end = findEndIndex(currentIndx, visibleRowsCountRef.current); + setTableVirtualBoundary({ start, end }); } } return ( - +
(null); +const reactContext = createContext(null); export const ReactTableProvider = reactContext.Provider; export function useReactTableContext() {