diff --git a/packages/grid/x-data-grid-pro/src/components/GridScrollArea.tsx b/packages/grid/x-data-grid-pro/src/components/GridScrollArea.tsx index 813277ac4eef..9055b4714e81 100644 --- a/packages/grid/x-data-grid-pro/src/components/GridScrollArea.tsx +++ b/packages/grid/x-data-grid-pro/src/components/GridScrollArea.tsx @@ -6,7 +6,7 @@ import { unstable_useEventCallback as useEventCallback, } from '@mui/utils'; import { styled } from '@mui/system'; -import { getTotalHeaderHeight } from '@mui/x-data-grid/internals'; +import { getTotalHeaderHeight, useTimeout } from '@mui/x-data-grid/internals'; import { GridEventListener, GridScrollParams, @@ -66,7 +66,7 @@ function GridScrollAreaRaw(props: ScrollAreaProps) { const { scrollDirection } = props; const rootRef = React.useRef(null); const apiRef = useGridApiContext(); - const timeout = React.useRef(); + const timeout = useTimeout(); const [dragging, setDragging] = React.useState(false); const [canScrollMore, setCanScrollMore] = React.useState(true); const densityFactor = useGridSelector(apiRef, gridDensityFactorSelector); @@ -124,24 +124,17 @@ function GridScrollAreaRaw(props: ScrollAreaProps) { offset = (offset - CLIFF) * SLOP + CLIFF; - clearTimeout(timeout.current); // Avoid freeze and inertia. - timeout.current = setTimeout(() => { + timeout.start(0, () => { apiRef.current.scroll({ left: scrollPosition.current.left + offset, top: scrollPosition.current.top, }); }); }, - [scrollDirection, apiRef], + [scrollDirection, apiRef, timeout], ); - React.useEffect(() => { - return () => { - clearTimeout(timeout.current); - }; - }, []); - const handleColumnHeaderDragStart = useEventCallback(() => { setDragging(true); }); diff --git a/packages/grid/x-data-grid/src/hooks/features/rows/useGridRows.ts b/packages/grid/x-data-grid/src/hooks/features/rows/useGridRows.ts index 0c3d11c30c30..2562e1c3d932 100644 --- a/packages/grid/x-data-grid/src/hooks/features/rows/useGridRows.ts +++ b/packages/grid/x-data-grid/src/hooks/features/rows/useGridRows.ts @@ -21,6 +21,7 @@ import { gridRowsDataRowIdToIdLookupSelector, gridRowMaximumTreeDepthSelector, } from './gridRowsSelector'; +import { useTimeout } from '../../utils/useTimeout'; import { GridSignature, useGridApiEventHandler } from '../../utils/useGridApiEventHandler'; import { GridStateInitializer } from '../../utils/useGridInitializeState'; import { useGridVisibleRows } from '../../utils/useGridVisibleRows'; @@ -89,7 +90,7 @@ export const useGridRows = ( const currentPage = useGridVisibleRows(apiRef, props); const lastUpdateMs = React.useRef(Date.now()); - const timeout = React.useRef(null); + const timeout = useTimeout(); const getRow = React.useCallback( (id) => { @@ -135,7 +136,6 @@ export const useGridRows = ( const throttledRowsChange = React.useCallback( ({ cache, throttle }: { cache: GridRowsInternalCache; throttle: boolean }) => { const run = () => { - timeout.current = null; lastUpdateMs.current = Date.now(); apiRef.current.setState((state) => ({ ...state, @@ -151,10 +151,7 @@ export const useGridRows = ( apiRef.current.forceUpdate(); }; - if (timeout.current) { - clearTimeout(timeout.current); - timeout.current = null; - } + timeout.clear(); apiRef.current.caches.rows = cache; @@ -165,13 +162,13 @@ export const useGridRows = ( const throttleRemainingTimeMs = props.throttleRowsMs - (Date.now() - lastUpdateMs.current); if (throttleRemainingTimeMs > 0) { - timeout.current = setTimeout(run, throttleRemainingTimeMs); + timeout.start(throttleRemainingTimeMs, run); return; } run(); }, - [props.throttleRowsMs, props.rowCount, props.loading, apiRef], + [props.throttleRowsMs, props.rowCount, props.loading, apiRef, timeout], ); /** @@ -583,17 +580,6 @@ export const useGridRows = ( props.signature === GridSignature.DataGrid ? 'private' : 'public', ); - /** - * EFFECTS - */ - React.useEffect(() => { - return () => { - if (timeout.current !== null) { - clearTimeout(timeout.current); - } - }; - }, []); - // The effect do not track any value defined synchronously during the 1st render by hooks called after `useGridRows` // As a consequence, the state generated by the 1st run of this useEffect will always be equal to the initialization one const isFirstRender = React.useRef(true); diff --git a/packages/grid/x-data-grid/src/internals/index.ts b/packages/grid/x-data-grid/src/internals/index.ts index 26ba0f5e30a6..40a9d112efda 100644 --- a/packages/grid/x-data-grid/src/internals/index.ts +++ b/packages/grid/x-data-grid/src/internals/index.ts @@ -114,6 +114,7 @@ export { getRenderableIndexes, } from '../hooks/features/virtualization/useGridVirtualScroller'; +export { useTimeout } from '../hooks/utils/useTimeout'; export { useGridVisibleRows, getVisibleRows } from '../hooks/utils/useGridVisibleRows'; export { useGridInitializeState } from '../hooks/utils/useGridInitializeState'; export type { GridStateInitializer } from '../hooks/utils/useGridInitializeState';