Compare commits

..

No commits in common. "18ec053e445fe445e50ad6658ecf40d8e7bce793" and "e6133b82fe5a6a918ed8c37d2dd2ecc10ac3050a" have entirely different histories.

3 changed files with 56 additions and 26 deletions

View File

@ -23,7 +23,7 @@ const FORMULA_INDICATOR_STYLES = {
const TEXTAREA_STYLES = {
width: '100%',
height: '3rem',
height: 'auto',
fieldSizing: 'content',
fontSize: 'inherit',
};
@ -32,6 +32,7 @@ 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,
@ -39,7 +40,7 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
}));
// Позиция ячейки
const [position, setPosition] = useState();
const [position, setPosition] = useState({ left: 0, width: 0, translateY: '' });
const textareaRef = useRef(null);
const refFinished = useRef(false);
@ -88,8 +89,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';
};
@ -101,6 +102,16 @@ 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;
@ -135,6 +146,7 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
}
}, [state, storageKey, onChange]);
// Завершение редактирования
const finishEditing = useCallback(() => {
if(refFinished.current) return;
refFinished.current = true;
@ -158,6 +170,7 @@ 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 => ({
@ -174,11 +187,12 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
}
}, [finishEditing]);
// Мемоизация стилей
const editorStyles = useMemo(() => ({
...EDITOR_STYLES,
left: position?.left || 0,
width: position?.width || 0,
transform: position?.translateY || 0,
left: position.left,
width: position.width,
transform: position.translateY,
}), [position]);
const textareaStyles = useMemo(() => ({
@ -190,7 +204,6 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
return (
<tr>
<td>
{position &&
<div style={editorStyles}>
{state.isFormulaMode && (
<div style={FORMULA_INDICATOR_STYLES}>fx</div>
@ -205,8 +218,6 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
placeholder={state.isFormulaMode ? 'Введите формулу (начинается с =)' : ''}
/>
</div>
}
</td>
</tr>
);

View File

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

View File

@ -1,8 +1,10 @@
// 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,
@ -20,6 +22,7 @@ const EditCellPortal = React.memo(({
const { endEditing: contextEndEditing } = useRealtime();
// Оптимизация: вычисляем позицию только при монтировании и изменении cell
useEffect(() => {
if (ref.current) {
const tbodyRef = ref.current.offsetParent?.offsetParent?.offsetParent;
@ -27,8 +30,9 @@ const EditCellPortal = React.memo(({
setRefTbody(tbodyRef);
}
}
}, []);
}, [refTbody]); // Добавляем refTbody в зависимости
// Мемоизация обработчика изменения
const handleChange = useCallback( (val) => {
table.setEditingCell(null);
try {
@ -49,6 +53,7 @@ const EditCellPortal = React.memo(({
}
}, [table, cell, onError]);
// Мемоизация пропсов для EditCell
const editCellProps = useMemo(() => ({
refCell: ref,
cell,
@ -60,6 +65,7 @@ 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(
@ -76,7 +82,9 @@ const EditCellPortal = React.memo(({
);
});
EditCellPortal.displayName = 'EditCellPortal';
// Основная функция getTableColumns
export const getTableColumns = ({
Cell,
EditCell,
@ -87,9 +95,11 @@ 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}`;
@ -99,6 +109,7 @@ 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;
@ -125,6 +136,7 @@ export const getTableColumns = ({
return props;
};
// Функция для получения кешированных пропсов Edit
const getCachedEditProps = (row, column, table) => {
const key = `${row.id}_${column.id}`;
@ -148,9 +160,11 @@ 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,
@ -161,9 +175,11 @@ 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}
@ -177,6 +193,7 @@ export const getTableColumns = ({
return editComponent;
};
// Рекурсивно обрабатываем вложенные колонки
if (col.columns?.length) {
processColumns(col.columns);
}
@ -185,6 +202,7 @@ export const getTableColumns = ({
processColumns(columns);
// Оптимизированная колонка с номерами строк
const rowNumber = {
accessorKey: 'sort_order',
header: '#',