Compare commits
No commits in common. "18ec053e445fe445e50ad6658ecf40d8e7bce793" and "e6133b82fe5a6a918ed8c37d2dd2ecc10ac3050a" have entirely different histories.
18ec053e44
...
e6133b82fe
@ -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,8 +146,9 @@ 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();
|
||||
@ -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,23 +204,20 @@ 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>
|
||||
)}
|
||||
<textarea
|
||||
ref={textareaRef}
|
||||
disabled={disabled}
|
||||
style={textareaStyles}
|
||||
onChange={handleChange}
|
||||
value={state.currentValue}
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder={state.isFormulaMode ? 'Введите формулу (начинается с =)' : ''}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
<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>
|
||||
);
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// components/RealtimeTable/index.js
|
||||
import React, { useState, useMemo, useRef, useEffect, useCallback, useTransition } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import {
|
||||
|
||||
@ -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: '#',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user