perf(table): ColumnResizer сообщает MRT начало и конец перетаскивания ширины
isResizingColumn выставляется на mousedown и снимается по mouseup, blur окна и размонтированию: пока тянут, MRT замораживает тело таблицы (design.md D3). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
61cafb44a6
commit
e5f4b3b965
@ -1,14 +1,28 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
const ColumnResizer = ({ reportDragDeltaX }) => {
|
||||
const ColumnResizer = ({ columnId, reportDragDeltaX, onDragStart, onDragEnd }) => {
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const isDraggingRef = useRef(false);
|
||||
const lastXRef = useRef(0);
|
||||
// HeaderCell создаёт колбэки на каждый рендер: держим последний в ref.
|
||||
const onDragEndRef = useRef(onDragEnd);
|
||||
onDragEndRef.current = onDragEnd;
|
||||
|
||||
// Единая точка завершения (mouseup, blur окна, размонтирование); идемпотентна.
|
||||
const finishDrag = useCallback(() => {
|
||||
if (!isDraggingRef.current) return;
|
||||
isDraggingRef.current = false;
|
||||
setIsDragging(false);
|
||||
onDragEndRef.current?.();
|
||||
}, []);
|
||||
|
||||
const handleMouseDown = (e) => {
|
||||
if (e.button !== 0) return;
|
||||
e.preventDefault();
|
||||
isDraggingRef.current = true;
|
||||
setIsDragging(true);
|
||||
lastXRef.current = e.clientX;
|
||||
onDragStart?.();
|
||||
};
|
||||
|
||||
const handleMouseMove = useCallback(
|
||||
@ -25,24 +39,27 @@ const ColumnResizer = ({ reportDragDeltaX }) => {
|
||||
[isDragging, reportDragDeltaX],
|
||||
);
|
||||
|
||||
const handleMouseUp = useCallback(() => {
|
||||
setIsDragging(false);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDragging) {
|
||||
window.addEventListener('mousemove', handleMouseMove);
|
||||
window.addEventListener('mouseup', handleMouseUp);
|
||||
}
|
||||
if (!isDragging) return;
|
||||
|
||||
window.addEventListener('mousemove', handleMouseMove);
|
||||
window.addEventListener('mouseup', finishDrag);
|
||||
window.addEventListener('blur', finishDrag);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('mousemove', handleMouseMove);
|
||||
window.removeEventListener('mouseup', handleMouseUp);
|
||||
window.removeEventListener('mouseup', finishDrag);
|
||||
window.removeEventListener('blur', finishDrag);
|
||||
};
|
||||
}, [isDragging, handleMouseMove, handleMouseUp]);
|
||||
}, [isDragging, handleMouseMove, finishDrag]);
|
||||
|
||||
// Размонтирование посреди перетаскивания не должно оставить MRT с isResizingColumn.
|
||||
// Отдельный эффект: очистка эффекта подписок срабатывает при каждой смене handleMouseMove.
|
||||
useEffect(() => () => finishDrag(), [finishDrag]);
|
||||
|
||||
return (
|
||||
<div
|
||||
data-col-resize-id={columnId}
|
||||
onMouseDown={handleMouseDown}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
|
||||
@ -2,6 +2,7 @@ import React, { useMemo } from 'react';
|
||||
import ColumnResizer from './ColumnResizer';
|
||||
import { formatHeaderYear } from '../utils/headerYearUtils';
|
||||
import { getOrderedVisibleColumns } from '../utils/columnLayoutUtils';
|
||||
import { endColumnResize, startColumnResize } from '../utils/columnResizeInfo';
|
||||
|
||||
const getColumnPinnedStyles = (column) => {
|
||||
const pinningPosition = column.getIsPinned();
|
||||
@ -174,7 +175,12 @@ const HeaderCell = ({ header, table, pinningPosition, onClick, onChangeWidth, bu
|
||||
}}>
|
||||
{header.isPlaceholder ? null : formatHeaderYear(column.columnDef.header, budgetYear)}
|
||||
</div>
|
||||
<ColumnResizer reportDragDeltaX={handleChangeWidth} />
|
||||
<ColumnResizer
|
||||
columnId={column.id}
|
||||
reportDragDeltaX={handleChangeWidth}
|
||||
onDragStart={() => table.setColumnSizingInfo(startColumnResize(column.id))}
|
||||
onDragEnd={() => table.setColumnSizingInfo(endColumnResize)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user