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';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
const ColumnResizer = ({ reportDragDeltaX }) => {
|
const ColumnResizer = ({ columnId, reportDragDeltaX, onDragStart, onDragEnd }) => {
|
||||||
const [isDragging, setIsDragging] = useState(false);
|
const [isDragging, setIsDragging] = useState(false);
|
||||||
|
const isDraggingRef = useRef(false);
|
||||||
const lastXRef = useRef(0);
|
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) => {
|
const handleMouseDown = (e) => {
|
||||||
if (e.button !== 0) return;
|
if (e.button !== 0) return;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
isDraggingRef.current = true;
|
||||||
setIsDragging(true);
|
setIsDragging(true);
|
||||||
lastXRef.current = e.clientX;
|
lastXRef.current = e.clientX;
|
||||||
|
onDragStart?.();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseMove = useCallback(
|
const handleMouseMove = useCallback(
|
||||||
@ -25,24 +39,27 @@ const ColumnResizer = ({ reportDragDeltaX }) => {
|
|||||||
[isDragging, reportDragDeltaX],
|
[isDragging, reportDragDeltaX],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleMouseUp = useCallback(() => {
|
|
||||||
setIsDragging(false);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isDragging) {
|
if (!isDragging) return;
|
||||||
window.addEventListener('mousemove', handleMouseMove);
|
|
||||||
window.addEventListener('mouseup', handleMouseUp);
|
window.addEventListener('mousemove', handleMouseMove);
|
||||||
}
|
window.addEventListener('mouseup', finishDrag);
|
||||||
|
window.addEventListener('blur', finishDrag);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('mousemove', handleMouseMove);
|
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 (
|
return (
|
||||||
<div
|
<div
|
||||||
|
data-col-resize-id={columnId}
|
||||||
onMouseDown={handleMouseDown}
|
onMouseDown={handleMouseDown}
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import React, { useMemo } from 'react';
|
|||||||
import ColumnResizer from './ColumnResizer';
|
import ColumnResizer from './ColumnResizer';
|
||||||
import { formatHeaderYear } from '../utils/headerYearUtils';
|
import { formatHeaderYear } from '../utils/headerYearUtils';
|
||||||
import { getOrderedVisibleColumns } from '../utils/columnLayoutUtils';
|
import { getOrderedVisibleColumns } from '../utils/columnLayoutUtils';
|
||||||
|
import { endColumnResize, startColumnResize } from '../utils/columnResizeInfo';
|
||||||
|
|
||||||
const getColumnPinnedStyles = (column) => {
|
const getColumnPinnedStyles = (column) => {
|
||||||
const pinningPosition = column.getIsPinned();
|
const pinningPosition = column.getIsPinned();
|
||||||
@ -174,7 +175,12 @@ const HeaderCell = ({ header, table, pinningPosition, onClick, onChangeWidth, bu
|
|||||||
}}>
|
}}>
|
||||||
{header.isPlaceholder ? null : formatHeaderYear(column.columnDef.header, budgetYear)}
|
{header.isPlaceholder ? null : formatHeaderYear(column.columnDef.header, budgetYear)}
|
||||||
</div>
|
</div>
|
||||||
<ColumnResizer reportDragDeltaX={handleChangeWidth} />
|
<ColumnResizer
|
||||||
|
columnId={column.id}
|
||||||
|
reportDragDeltaX={handleChangeWidth}
|
||||||
|
onDragStart={() => table.setColumnSizingInfo(startColumnResize(column.id))}
|
||||||
|
onDragEnd={() => table.setColumnSizingInfo(endColumnResize)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user