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 = {
|
const TEXTAREA_STYLES = {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '3rem',
|
height: 'auto',
|
||||||
fieldSizing: 'content',
|
fieldSizing: 'content',
|
||||||
fontSize: 'inherit',
|
fontSize: 'inherit',
|
||||||
};
|
};
|
||||||
@ -32,6 +32,7 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
|
|||||||
const { endEditing: contextEndEditing } = useRealtime();
|
const { endEditing: contextEndEditing } = useRealtime();
|
||||||
const storageKey = `formula_${tableId}_${cellId}`;
|
const storageKey = `formula_${tableId}_${cellId}`;
|
||||||
|
|
||||||
|
// Объединенное состояние
|
||||||
const [state, setState] = useState(() => ({
|
const [state, setState] = useState(() => ({
|
||||||
currentValue: value,
|
currentValue: value,
|
||||||
displayValue: 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 textareaRef = useRef(null);
|
||||||
|
|
||||||
const refFinished = useRef(false);
|
const refFinished = useRef(false);
|
||||||
@ -88,8 +89,8 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
|
|||||||
if (!el) return;
|
if (!el) return;
|
||||||
|
|
||||||
const resize = () => {
|
const resize = () => {
|
||||||
|
el.style.height = 'auto';
|
||||||
el.style.minHeight = '3rem';
|
el.style.minHeight = '3rem';
|
||||||
el.style.height = '3rem';
|
|
||||||
el.style.height = el.scrollHeight + 'px';
|
el.style.height = el.scrollHeight + 'px';
|
||||||
el.style.maxHeight = '180px';
|
el.style.maxHeight = '180px';
|
||||||
};
|
};
|
||||||
@ -101,6 +102,16 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
|
|||||||
return () => observer.disconnect();
|
return () => observer.disconnect();
|
||||||
}, [state.currentValue]);
|
}, [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 handleSave = useCallback(() => {
|
||||||
const { currentValue } = state;
|
const { currentValue } = state;
|
||||||
|
|
||||||
@ -135,6 +146,7 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
|
|||||||
}
|
}
|
||||||
}, [state, storageKey, onChange]);
|
}, [state, storageKey, onChange]);
|
||||||
|
|
||||||
|
// Завершение редактирования
|
||||||
const finishEditing = useCallback(() => {
|
const finishEditing = useCallback(() => {
|
||||||
if(refFinished.current) return;
|
if(refFinished.current) return;
|
||||||
refFinished.current = true;
|
refFinished.current = true;
|
||||||
@ -158,6 +170,7 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
|
|||||||
return () => document.removeEventListener('mousedown', handleClickOutside);
|
return () => document.removeEventListener('mousedown', handleClickOutside);
|
||||||
}, [finishEditing]);
|
}, [finishEditing]);
|
||||||
|
|
||||||
|
// Обработчики событий
|
||||||
const handleChange = useCallback((e) => {
|
const handleChange = useCallback((e) => {
|
||||||
const value = e.target.value;
|
const value = e.target.value;
|
||||||
setState(prev => ({
|
setState(prev => ({
|
||||||
@ -174,11 +187,12 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
|
|||||||
}
|
}
|
||||||
}, [finishEditing]);
|
}, [finishEditing]);
|
||||||
|
|
||||||
|
// Мемоизация стилей
|
||||||
const editorStyles = useMemo(() => ({
|
const editorStyles = useMemo(() => ({
|
||||||
...EDITOR_STYLES,
|
...EDITOR_STYLES,
|
||||||
left: position?.left || 0,
|
left: position.left,
|
||||||
width: position?.width || 0,
|
width: position.width,
|
||||||
transform: position?.translateY || 0,
|
transform: position.translateY,
|
||||||
}), [position]);
|
}), [position]);
|
||||||
|
|
||||||
const textareaStyles = useMemo(() => ({
|
const textareaStyles = useMemo(() => ({
|
||||||
@ -190,7 +204,6 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
|
|||||||
return (
|
return (
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
{position &&
|
|
||||||
<div style={editorStyles}>
|
<div style={editorStyles}>
|
||||||
{state.isFormulaMode && (
|
{state.isFormulaMode && (
|
||||||
<div style={FORMULA_INDICATOR_STYLES}>fx</div>
|
<div style={FORMULA_INDICATOR_STYLES}>fx</div>
|
||||||
@ -205,8 +218,6 @@ const EditCell = memo(({ refCell, onChange, disabled, value, tableId, cellId, ta
|
|||||||
placeholder={state.isFormulaMode ? 'Введите формулу (начинается с =)' : ''}
|
placeholder={state.isFormulaMode ? 'Введите формулу (начинается с =)' : ''}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// components/RealtimeTable/index.js
|
||||||
import React, { useState, useMemo, useRef, useEffect, useCallback, useTransition } from 'react';
|
import React, { useState, useMemo, useRef, useEffect, useCallback, useTransition } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import {
|
import {
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
|
// getTableColumns.js
|
||||||
import React, { useEffect, useRef, useState, useMemo, useCallback } from 'react';
|
import React, { useEffect, useRef, useState, useMemo, useCallback } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router';
|
||||||
import { useRealtime } from './contexts/RealtimeContext';
|
import { useRealtime } from './contexts/RealtimeContext';
|
||||||
|
|
||||||
|
// Мемоизированный компонент EditCellPortal
|
||||||
const EditCellPortal = React.memo(({
|
const EditCellPortal = React.memo(({
|
||||||
cell,
|
cell,
|
||||||
table,
|
table,
|
||||||
@ -20,6 +22,7 @@ const EditCellPortal = React.memo(({
|
|||||||
|
|
||||||
const { endEditing: contextEndEditing } = useRealtime();
|
const { endEditing: contextEndEditing } = useRealtime();
|
||||||
|
|
||||||
|
// Оптимизация: вычисляем позицию только при монтировании и изменении cell
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ref.current) {
|
if (ref.current) {
|
||||||
const tbodyRef = ref.current.offsetParent?.offsetParent?.offsetParent;
|
const tbodyRef = ref.current.offsetParent?.offsetParent?.offsetParent;
|
||||||
@ -27,8 +30,9 @@ const EditCellPortal = React.memo(({
|
|||||||
setRefTbody(tbodyRef);
|
setRefTbody(tbodyRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, []);
|
}, [refTbody]); // Добавляем refTbody в зависимости
|
||||||
|
|
||||||
|
// Мемоизация обработчика изменения
|
||||||
const handleChange = useCallback( (val) => {
|
const handleChange = useCallback( (val) => {
|
||||||
table.setEditingCell(null);
|
table.setEditingCell(null);
|
||||||
try {
|
try {
|
||||||
@ -49,6 +53,7 @@ const EditCellPortal = React.memo(({
|
|||||||
}
|
}
|
||||||
}, [table, cell, onError]);
|
}, [table, cell, onError]);
|
||||||
|
|
||||||
|
// Мемоизация пропсов для EditCell
|
||||||
const editCellProps = useMemo(() => ({
|
const editCellProps = useMemo(() => ({
|
||||||
refCell: ref,
|
refCell: ref,
|
||||||
cell,
|
cell,
|
||||||
@ -60,6 +65,7 @@ const EditCellPortal = React.memo(({
|
|||||||
cellId: `${cell.row.id}_${cell.column.id}`,
|
cellId: `${cell.row.id}_${cell.column.id}`,
|
||||||
}), [cell, isEditable, handleChange, tableKey, table]);
|
}), [cell, isEditable, handleChange, tableKey, table]);
|
||||||
|
|
||||||
|
// Мемоизация портала
|
||||||
const portalContent = useMemo(() => {
|
const portalContent = useMemo(() => {
|
||||||
if (!refTbody || isSaving) return null;
|
if (!refTbody || isSaving) return null;
|
||||||
return createPortal(
|
return createPortal(
|
||||||
@ -76,7 +82,9 @@ const EditCellPortal = React.memo(({
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
EditCellPortal.displayName = 'EditCellPortal';
|
||||||
|
|
||||||
|
// Основная функция getTableColumns
|
||||||
export const getTableColumns = ({
|
export const getTableColumns = ({
|
||||||
Cell,
|
Cell,
|
||||||
EditCell,
|
EditCell,
|
||||||
@ -87,9 +95,11 @@ export const getTableColumns = ({
|
|||||||
const columnColors = { ...columnsConfig.colors };
|
const columnColors = { ...columnsConfig.colors };
|
||||||
const columns = structuredClone(columnsConfig.columns);
|
const columns = structuredClone(columnsConfig.columns);
|
||||||
|
|
||||||
|
// Кэши для вычисленных значений
|
||||||
const cellPropsCache = new WeakMap();
|
const cellPropsCache = new WeakMap();
|
||||||
const editPropsCache = new WeakMap();
|
const editPropsCache = new WeakMap();
|
||||||
|
|
||||||
|
// Функция для получения кешированных пропсов Cell
|
||||||
const getCachedCellProps = (row, column, table) => {
|
const getCachedCellProps = (row, column, table) => {
|
||||||
const key = `${row.id}_${column.id}`;
|
const key = `${row.id}_${column.id}`;
|
||||||
|
|
||||||
@ -99,6 +109,7 @@ export const getTableColumns = ({
|
|||||||
|
|
||||||
const rowCache = cellPropsCache.get(row);
|
const rowCache = cellPropsCache.get(row);
|
||||||
if (rowCache[key]) {
|
if (rowCache[key]) {
|
||||||
|
// Проверяем, не изменились ли фильтры
|
||||||
const cached = rowCache[key];
|
const cached = rowCache[key];
|
||||||
const currentGlobalFilter = table.getState().globalFilter;
|
const currentGlobalFilter = table.getState().globalFilter;
|
||||||
const currentColumnFilter = table.getState().columnFilters?.find(f => f.id === column.id)?.value;
|
const currentColumnFilter = table.getState().columnFilters?.find(f => f.id === column.id)?.value;
|
||||||
@ -125,6 +136,7 @@ export const getTableColumns = ({
|
|||||||
return props;
|
return props;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Функция для получения кешированных пропсов Edit
|
||||||
const getCachedEditProps = (row, column, table) => {
|
const getCachedEditProps = (row, column, table) => {
|
||||||
const key = `${row.id}_${column.id}`;
|
const key = `${row.id}_${column.id}`;
|
||||||
|
|
||||||
@ -148,9 +160,11 @@ export const getTableColumns = ({
|
|||||||
// Оптимизированная функция processColumns
|
// Оптимизированная функция processColumns
|
||||||
const processColumns = (columns) => {
|
const processColumns = (columns) => {
|
||||||
columns.forEach((col) => {
|
columns.forEach((col) => {
|
||||||
|
// Оптимизированный Cell
|
||||||
col.Cell = ({ cell, table, column, row }) => {
|
col.Cell = ({ cell, table, column, row }) => {
|
||||||
const props = getCachedCellProps(row, column, table);
|
const props = getCachedCellProps(row, column, table);
|
||||||
|
|
||||||
|
// Используем useMemo для мемоизации пропсов
|
||||||
const cellProps = useMemo(() => ({
|
const cellProps = useMemo(() => ({
|
||||||
row,
|
row,
|
||||||
column,
|
column,
|
||||||
@ -161,9 +175,11 @@ export const getTableColumns = ({
|
|||||||
return <Cell {...cellProps} />;
|
return <Cell {...cellProps} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Оптимизированный Edit
|
||||||
col.Edit = ({ cell, table, row, column }) => {
|
col.Edit = ({ cell, table, row, column }) => {
|
||||||
const props = getCachedEditProps(row, column, table);
|
const props = getCachedEditProps(row, column, table);
|
||||||
|
|
||||||
|
// Мемоизируем компонент EditCellPortal
|
||||||
const editComponent = useMemo(() => (
|
const editComponent = useMemo(() => (
|
||||||
<EditCellPortal
|
<EditCellPortal
|
||||||
cell={cell}
|
cell={cell}
|
||||||
@ -177,6 +193,7 @@ export const getTableColumns = ({
|
|||||||
return editComponent;
|
return editComponent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Рекурсивно обрабатываем вложенные колонки
|
||||||
if (col.columns?.length) {
|
if (col.columns?.length) {
|
||||||
processColumns(col.columns);
|
processColumns(col.columns);
|
||||||
}
|
}
|
||||||
@ -185,6 +202,7 @@ export const getTableColumns = ({
|
|||||||
|
|
||||||
processColumns(columns);
|
processColumns(columns);
|
||||||
|
|
||||||
|
// Оптимизированная колонка с номерами строк
|
||||||
const rowNumber = {
|
const rowNumber = {
|
||||||
accessorKey: 'sort_order',
|
accessorKey: 'sort_order',
|
||||||
header: '#',
|
header: '#',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user