Compare commits

..

2 Commits

Author SHA1 Message Date
18ec053e44 Merge pull request 'правки' (#47) from table-optimization-fix into test
Reviewed-on: #47
2026-07-24 17:28:19 +03:00
PotapovaA
e4726b6284 правки 2026-07-24 17:26:05 +03:00
3 changed files with 26 additions and 56 deletions

View File

@ -23,7 +23,7 @@ const FORMULA_INDICATOR_STYLES = {
const TEXTAREA_STYLES = {
width: '100%',
height: 'auto',
height: '3rem',
fieldSizing: 'content',
fontSize: 'inherit',
};
@ -32,7 +32,6 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
const { endEditing: contextEndEditing } = useRealtime();
const storageKey = `formula_${tableId}_${cellId}`;
// Объединенное состояние
const [state, setState] = useState(() => ({
currentValue: value,
displayValue: value,
@ -40,7 +39,7 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
}));
// Позиция ячейки
const [position, setPosition] = useState({ left: 0, width: 0, translateY: '' });
const [position, setPosition] = useState();
const textareaRef = useRef(null);
const refFinished = useRef(false);
@ -89,8 +88,8 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
if (!el) return;
const resize = () => {
el.style.height = 'auto';
el.style.minHeight = '3rem';
el.style.height = '3rem';
el.style.height = el.scrollHeight + 'px';
el.style.maxHeight = '180px';
};
@ -102,16 +101,6 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
return () => observer.disconnect();
}, [state.currentValue]);
// Фокус при монтировании
useEffect(() => {
const el = textareaRef.current;
if (el && !disabled) {
el.focus();
el.setSelectionRange(el.value.length, el.value.length);
}
}, [disabled]);
// Сохранение
const handleSave = useCallback(() => {
const { currentValue } = state;
@ -146,9 +135,8 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
}
}, [state, storageKey, onChange]);
// Завершение редактирования
const finishEditing = useCallback(() => {
if(refFinished.current) return;
if (refFinished.current) return;
refFinished.current = true;
if (!disabled) {
handleSave();
@ -170,7 +158,6 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
return () => document.removeEventListener('mousedown', handleClickOutside);
}, [finishEditing]);
// Обработчики событий
const handleChange = useCallback((e) => {
const value = e.target.value;
setState(prev => ({
@ -187,12 +174,11 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
}
}, [finishEditing]);
// Мемоизация стилей
const editorStyles = useMemo(() => ({
...EDITOR_STYLES,
left: position.left,
width: position.width,
transform: position.translateY,
left: position?.left || 0,
width: position?.width || 0,
transform: position?.translateY || 0,
}), [position]);
const textareaStyles = useMemo(() => ({
@ -204,20 +190,23 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
return (
<tr>
<td>
<div style={editorStyles}>
{state.isFormulaMode && (
<div style={FORMULA_INDICATOR_STYLES}>fx</div>
)}
<textarea
ref={textareaRef}
disabled={disabled}
style={textareaStyles}
onChange={handleChange}
value={state.currentValue}
onKeyDown={handleKeyDown}
placeholder={state.isFormulaMode ? 'Введите формулу (начинается с =)' : ''}
/>
</div>
{position &&
<div style={editorStyles}>
{state.isFormulaMode && (
<div style={FORMULA_INDICATOR_STYLES}>fx</div>
)}
<textarea
ref={textareaRef}
disabled={disabled}
style={textareaStyles}
onChange={handleChange}
value={state.currentValue}
onKeyDown={handleKeyDown}
placeholder={state.isFormulaMode ? 'Введите формулу (начинается с =)' : ''}
/>
</div>
}
</td>
</tr>
);

View File

@ -1,4 +1,3 @@
// components/RealtimeTable/index.js
import React, { useState, useMemo, useRef, useEffect, useCallback, useTransition } from 'react';
import { createPortal } from 'react-dom';
import {

View File

@ -1,10 +1,8 @@
// getTableColumns.js
import React, { useEffect, useRef, useState, useMemo, useCallback } from 'react';
import { createPortal } from 'react-dom';
import { useParams } from 'react-router';
import { useRealtime } from './contexts/RealtimeContext';
// Мемоизированный компонент EditCellPortal
const EditCellPortal = React.memo(({
cell,
table,
@ -22,7 +20,6 @@ const EditCellPortal = React.memo(({
const { endEditing: contextEndEditing } = useRealtime();
// Оптимизация: вычисляем позицию только при монтировании и изменении cell
useEffect(() => {
if (ref.current) {
const tbodyRef = ref.current.offsetParent?.offsetParent?.offsetParent;
@ -30,9 +27,8 @@ const EditCellPortal = React.memo(({
setRefTbody(tbodyRef);
}
}
}, [refTbody]); // Добавляем refTbody в зависимости
}, []);
// Мемоизация обработчика изменения
const handleChange = useCallback( (val) => {
table.setEditingCell(null);
try {
@ -53,7 +49,6 @@ const EditCellPortal = React.memo(({
}
}, [table, cell, onError]);
// Мемоизация пропсов для EditCell
const editCellProps = useMemo(() => ({
refCell: ref,
cell,
@ -65,7 +60,6 @@ const EditCellPortal = React.memo(({
cellId: `${cell.row.id}_${cell.column.id}`,
}), [cell, isEditable, handleChange, tableKey, table]);
// Мемоизация портала
const portalContent = useMemo(() => {
if (!refTbody || isSaving) return null;
return createPortal(
@ -77,14 +71,12 @@ const EditCellPortal = React.memo(({
return (
<>
<div ref={ref} style={{ width: '100%', height: '100%' }} />
{portalContent}
{portalContent}
</>
);
});
EditCellPortal.displayName = 'EditCellPortal';
// Основная функция getTableColumns
export const getTableColumns = ({
Cell,
EditCell,
@ -95,11 +87,9 @@ export const getTableColumns = ({
const columnColors = { ...columnsConfig.colors };
const columns = structuredClone(columnsConfig.columns);
// Кэши для вычисленных значений
const cellPropsCache = new WeakMap();
const editPropsCache = new WeakMap();
// Функция для получения кешированных пропсов Cell
const getCachedCellProps = (row, column, table) => {
const key = `${row.id}_${column.id}`;
@ -109,7 +99,6 @@ export const getTableColumns = ({
const rowCache = cellPropsCache.get(row);
if (rowCache[key]) {
// Проверяем, не изменились ли фильтры
const cached = rowCache[key];
const currentGlobalFilter = table.getState().globalFilter;
const currentColumnFilter = table.getState().columnFilters?.find(f => f.id === column.id)?.value;
@ -136,7 +125,6 @@ export const getTableColumns = ({
return props;
};
// Функция для получения кешированных пропсов Edit
const getCachedEditProps = (row, column, table) => {
const key = `${row.id}_${column.id}`;
@ -160,11 +148,9 @@ export const getTableColumns = ({
// Оптимизированная функция processColumns
const processColumns = (columns) => {
columns.forEach((col) => {
// Оптимизированный Cell
col.Cell = ({ cell, table, column, row }) => {
const props = getCachedCellProps(row, column, table);
// Используем useMemo для мемоизации пропсов
const cellProps = useMemo(() => ({
row,
column,
@ -175,11 +161,9 @@ export const getTableColumns = ({
return <Cell {...cellProps} />;
};
// Оптимизированный Edit
col.Edit = ({ cell, table, row, column }) => {
const props = getCachedEditProps(row, column, table);
// Мемоизируем компонент EditCellPortal
const editComponent = useMemo(() => (
<EditCellPortal
cell={cell}
@ -193,7 +177,6 @@ export const getTableColumns = ({
return editComponent;
};
// Рекурсивно обрабатываем вложенные колонки
if (col.columns?.length) {
processColumns(col.columns);
}
@ -202,7 +185,6 @@ export const getTableColumns = ({
processColumns(columns);
// Оптимизированная колонка с номерами строк
const rowNumber = {
accessorKey: 'sort_order',
header: '#',