fix: 컬럼 리사이즈 무한 리렌더링 및 원위치 복귀 문제 해결
- ref callback에서 state 업데이트 제거 - useEffect + setTimeout으로 초기 너비 측정 (한 번만) - hasInitializedWidths useRef로 중복 측정 방지 - columnRefs useRef로 DOM 직접 참조 - 드래그 중 리렌더링 없이 DOM만 직접 조작 - 부드럽고 정확한 리사이즈 구현 완료
This commit is contained in:
parent
511884f323
commit
3332c87293
|
|
@ -107,6 +107,8 @@ export const InteractiveDataTable: React.FC<InteractiveDataTableProps> = ({
|
|||
const [total, setTotal] = useState(0);
|
||||
const [selectedRows, setSelectedRows] = useState<Set<number>>(new Set());
|
||||
const [columnWidths, setColumnWidths] = useState<Record<string, number>>({});
|
||||
const hasInitializedWidthsRef = useRef(false);
|
||||
const columnRefs = useRef<Record<string, HTMLTableCellElement | null>>({});
|
||||
|
||||
// SaveModal 상태 (등록/수정 통합)
|
||||
const [showSaveModal, setShowSaveModal] = useState(false);
|
||||
|
|
@ -409,6 +411,35 @@ export const InteractiveDataTable: React.FC<InteractiveDataTableProps> = ({
|
|||
// 페이지 크기 설정
|
||||
const pageSize = component.pagination?.pageSize || 10;
|
||||
|
||||
// 초기 컬럼 너비 측정 (한 번만)
|
||||
useEffect(() => {
|
||||
if (!hasInitializedWidthsRef.current && visibleColumns.length > 0) {
|
||||
// 약간의 지연을 두고 DOM이 완전히 렌더링된 후 측정
|
||||
const timer = setTimeout(() => {
|
||||
const newWidths: Record<string, number> = {};
|
||||
let hasAnyWidth = false;
|
||||
|
||||
visibleColumns.forEach((column) => {
|
||||
const thElement = columnRefs.current[column.id];
|
||||
if (thElement) {
|
||||
const measuredWidth = thElement.offsetWidth;
|
||||
if (measuredWidth > 0) {
|
||||
newWidths[column.id] = measuredWidth;
|
||||
hasAnyWidth = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (hasAnyWidth) {
|
||||
setColumnWidths(newWidths);
|
||||
hasInitializedWidthsRef.current = true;
|
||||
}
|
||||
}, 100);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [visibleColumns]);
|
||||
|
||||
// 데이터 로드 함수
|
||||
const loadData = useCallback(
|
||||
async (page: number = 1, searchParams: Record<string, any> = {}) => {
|
||||
|
|
@ -1939,18 +1970,7 @@ export const InteractiveDataTable: React.FC<InteractiveDataTableProps> = ({
|
|||
return (
|
||||
<TableHead
|
||||
key={column.id}
|
||||
ref={(el) => {
|
||||
// 첫 렌더링 시 실제 너비를 측정해서 상태에 저장
|
||||
if (el && !columnWidth) {
|
||||
const measuredWidth = el.offsetWidth;
|
||||
if (measuredWidth > 0) {
|
||||
setColumnWidths(prev => ({
|
||||
...prev,
|
||||
[column.id]: measuredWidth
|
||||
}));
|
||||
}
|
||||
}
|
||||
}}
|
||||
ref={(el) => (columnRefs.current[column.id] = el)}
|
||||
className="relative bg-gradient-to-r from-gray-50 to-slate-50 px-4 font-semibold text-gray-700 select-none"
|
||||
style={{
|
||||
width: columnWidth ? `${columnWidth}px` : undefined,
|
||||
|
|
@ -1968,7 +1988,7 @@ export const InteractiveDataTable: React.FC<InteractiveDataTableProps> = ({
|
|||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const thElement = e.currentTarget.parentElement as HTMLTableCellElement;
|
||||
const thElement = columnRefs.current[column.id];
|
||||
if (!thElement) return;
|
||||
|
||||
const startX = e.clientX;
|
||||
|
|
|
|||
|
|
@ -247,6 +247,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
const [columnWidths, setColumnWidths] = useState<Record<string, number>>({});
|
||||
const columnRefs = useRef<Record<string, HTMLTableCellElement | null>>({});
|
||||
const [isAllSelected, setIsAllSelected] = useState(false);
|
||||
const hasInitializedWidths = useRef(false);
|
||||
|
||||
// 필터 설정 관련 상태
|
||||
const [isFilterSettingOpen, setIsFilterSettingOpen] = useState(false);
|
||||
|
|
@ -794,6 +795,35 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
}
|
||||
}, [tableConfig.refreshInterval, isDesignMode]);
|
||||
|
||||
// 초기 컬럼 너비 측정 (한 번만)
|
||||
useEffect(() => {
|
||||
if (!hasInitializedWidths.current && visibleColumns.length > 0) {
|
||||
// 약간의 지연을 두고 DOM이 완전히 렌더링된 후 측정
|
||||
const timer = setTimeout(() => {
|
||||
const newWidths: Record<string, number> = {};
|
||||
let hasAnyWidth = false;
|
||||
|
||||
visibleColumns.forEach((column) => {
|
||||
const thElement = columnRefs.current[column.columnName];
|
||||
if (thElement) {
|
||||
const measuredWidth = thElement.offsetWidth;
|
||||
if (measuredWidth > 0) {
|
||||
newWidths[column.columnName] = measuredWidth;
|
||||
hasAnyWidth = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (hasAnyWidth) {
|
||||
setColumnWidths(newWidths);
|
||||
hasInitializedWidths.current = true;
|
||||
}
|
||||
}, 100);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [visibleColumns]);
|
||||
|
||||
// ========================================
|
||||
// 페이지네이션 JSX
|
||||
// ========================================
|
||||
|
|
@ -1027,19 +1057,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
return (
|
||||
<th
|
||||
key={column.columnName}
|
||||
ref={(el) => {
|
||||
columnRefs.current[column.columnName] = el;
|
||||
// 첫 렌더링 시 실제 너비를 측정해서 상태에 저장
|
||||
if (el && !columnWidth) {
|
||||
const measuredWidth = el.offsetWidth;
|
||||
if (measuredWidth > 0) {
|
||||
setColumnWidths(prev => ({
|
||||
...prev,
|
||||
[column.columnName]: measuredWidth
|
||||
}));
|
||||
}
|
||||
}
|
||||
}}
|
||||
ref={(el) => (columnRefs.current[column.columnName] = el)}
|
||||
className={cn(
|
||||
"relative h-10 px-2 py-2 text-xs font-semibold text-foreground overflow-hidden text-ellipsis bg-background select-none sm:h-12 sm:px-6 sm:py-3 sm:text-sm sm:whitespace-nowrap",
|
||||
column.sortable && "cursor-pointer"
|
||||
|
|
|
|||
Loading…
Reference in New Issue