Сложный компонент таблицы React с выбором строки, вызывающим скачок прокрутки – ищем предложения по оптимизации ⇐ Javascript
Сложный компонент таблицы React с выбором строки, вызывающим скачок прокрутки – ищем предложения по оптимизации
Сейчас я работаю над сложным компонентом таблицы React, который вызывает некоторые проблемы с производительностью и удобством использования. Основная проблема заключается в том, что при выборе строк позиция прокрутки таблицы смещается, что дезориентирует пользователя. Мне бы хотелось услышать ваши идеи и предложения о том, как оптимизировать этот компонент и устранить указанную проблему.
Обзор компонентов:
Компонент таблицы (TableComponent), который я разрабатываю, использует пакет React-base-table. Вот некоторые из его функций и возможностей:
Динамический выбор строк. Пользователи могут выбирать строки простым щелчком мыши или несколько строк с помощью клавиши Shift. Выборки визуально выделяются, а списком выбранных строк можно управлять вне этой таблицы. Ими также можно манипулировать за пределами этой таблицы с помощью компонента SelectedRowsSummary для сохранения или редактирования последовательностей.
Фильтрация. Диалоговое окно фильтрации позволяет пользователям применять фильтры к определенным столбцам. Активные фильтры выделяют заголовки столбцов курсивом.
Изменение порядка столбцов. Изменить порядок столбцов можно в отдельном диалоговом окне.
Сортировка: столбцы можно сортировать, и компонент отслеживает текущие состояния сортировки. . Восстановление состояния. Компонент может восстанавливать свое состояние, включая примененные фильтры и порядок сортировки, из локального хранилища.
Технические проблемы:
Переход позиции прокрутки: при выборе строк позиция прокрутки таблицы неожиданно смещается. Я попытался сохранить положение прокрутки в ссылке, а затем восстановить его, но это непростое решение.
Монтаж и размонтирование. Из-за динамического характера таблицы и способа работы React компоненты часто монтируются и размонтируются. Такое поведение приводит к тому, что ссылка на таблицу иногда не определена при запуске эффекта макета. В качестве обходного пути я напрямую запрашиваю DOM, чтобы получить прокручиваемый элемент, но я знаю, что это не метод React.
Эффективность: текущая структура и логика, особенно с учетом всей памяти и управления состоянием, возможно, не самая эффективная. Я обеспокоен тем, что это может привести к проблемам с производительностью.
Ищу предложения:
Меня особенно интересует информация о:
Как сохранить плавность положения прокрутки после выбора строки.
Как эффективно управлять состоянием, особенно с таким динамическим компонентом.
Существует ли более «React-подобный» способ решения проблем, с которыми я сталкиваюсь, вместо прямого запроса к DOM.
Любые другие общие оптимизации или рекомендации, которые можно применить к этому компоненту.
Весь код соответствующих компонентов:
Таблица
импортировать React, {useState, useEffect, useMemo, useCallback, useRef, useLayoutEffect } из «реагировать»; импортировать таблицу, { AutoResizer, Column, ColumnShape } из «реагировать-базовой таблицы»; импортировать {Уведомление} из '@sms/plasma-ui'; импортировать момент из «момента»; импортировать стили из «styled-comments»; импортировать { pssApi } из '../../services'; импортировать {ReorderColumnsDialog, SelectedRowsSummary, FilterDialog} из './comComponents'; импортировать {isSameSlab, extractAllSlabs, getData, handleData} из './utils'; импортировать 'реагировать-базовую таблицу/styles.css'; импортировать html2canvas из «html2canvas»; const TableComponent = ({ столбцы, данные, мультизначениефильтр, маршрут, }: { столбцы: любой []; данные: любые[]; multiValueFilter: любой; маршрут: любой; }) => { const [isDialogOpen, setDialogOpen] = useState (false); const [selectedColumn, setSelectedColumn] = useState (null); const [currentFilterValue, setCurrentFilterValue] = useState (не определено); const [selectedRowIds, setSelectedRowIds] = useState([]); const [selectedRowIdsOld, setSelectedRowIdsOld] = useState([]); const [firstRowIndex, setFirstRowIndex] = useState (null); const [reorderDialogOpen, setReorderDialogOpen] = useState (false); const [appliedFilters, setAppliedFilters] = useState>({}); const [sortConfig, setSortConfig] = useState (null); const [dialogPosition, setDialogPosition] = useState({x: 0, y: 0 }); const [dialogsState, setDialogsState] = useState>({}); const [showSelectedOnTop, setShowSelectedOnTop] = useState (false); const [sequenceName, setSequenceName] = useState(''); const [sequenceId, setSequenceId] = useState (null); const [startDate, setStartDate] = useState (не определено); const [casterType, setCasterType] = useState (null); const [oneCasterChecked, setOneCasterChecked] = useState (false); const [currentColumns, setCurrentColumns] = useState(() => getData(columns)); const [isEdition, setIsEdition] = useState(false); const [dataScenario, setDataScenario] = useState (null); const ScrollPositionRef = useRef (0); const sortStatesConstructorFunction = () => { return currentColumns.reduce((согл.: любой, столбец: любой) => { если (столбец?.defaultSort) { acc[column.accessor] = columns.defaultSort; } возврат акк; }, {}); }; const [sortStates, setSortStates] = useState>(sortStatesConstructorFunction); const singleSort = (данные: любой[], dataKey: строка, порядок: 'по возрастанию' | 'по убыванию') => { return [...data].sort((a, b) => { const dir = порядок === 'по возрастанию'? 1:-1; if (a[dataKey] > b[dataKey]) вернуть каталог; если (a[dataKey] { setShowSelectedOnTop((prev) => !prev); }, []); const handleClearAllFilters = useCallback(() => { setAppliedFilters({}); setSortConfig (ноль); setSortStates(sortStatesConstructorFunction); if (isEdition && последовательностьId) { localStorage.removeItem(`sequenceTableState_${sequenceId}`); } }, [setAppliedFilters, setSortConfig, isEdition, SequenceId]); const filteredAndSortedData = useMemo(() => { пусть выходные данные = multiValueFilter (данные, applyFilters); если (сортКонфиг) { const {dataKey, заказ} = sortConfig; выходные данные = SingleSort (выходные данные, ключ данных, порядок); } если (showSelectedOnTop) { const selectedItems = []; const unselectedItems = [...outputData]; for (const rowId of selectedRowIds) { const index = unselectedItems.findIndex((item) => item.id === rowId); если (индекс !== -1) { selectedItems.push(unselectedItems[индекс]); unselectedItems.splice(индекс, 1); } } return [...selectedItems, ...unselectedItems]; } вернуть выходные данные; }, [appliedFilters, data, multiValueFilter, sortConfig, selectedRowIds, showSelectedOnTop]); const setFilter = useCallback( ( ColumnAccessor: строка, ценить: | нить | нить[] | { datetime: { startDate: moment.Moment | нулевой; КонечнаяДата: момент.Момент | нулевой } } | неопределенный, ) => { setAppliedFilters((предыдущий) => ({ ...предыдущий, [columnAccessor]: значение, })); }, [setAppliedFilters], ); const onColumnSort = useCallback( ({ столбец, ключ, порядок }: любой) => { пусть dataKey = columns.dataKey ?? столбец.аксессор; setSortStates((предыдущая) => { if (prev[key] === 'desc') { const newState = { ...prev }; удалить newState[ключ]; вернуть новое состояние; } return { ...prev, [ключ]: заказ }; }); setSortConfig({ключ, заказ, dataKey}); }, [setSortStates, setSortConfig], ); const updateDialogState = useCallback( (аксессор: строка, новые значения: любые) => { setDialogsState((предыдущая) => ({ ...предыдущий, [аксессуар]: { ...предыдущая[аксессуар], ...новые значения, }, })); }, [setDialogsState], ); const toggleRowSelection = useCallback( async (rowId: любой, индекс: число, ShiftKey: логическое значение) => { const ScrollableElement = document.querySelector('[class*=BaseTable__body]'); если (прокручиваемыйЭлемент) { ScrollPositionRef.current = прокручиваемыйЭлемент.scrollTop; } setSelectedRowIds((prevIds: любой) => { const newSelectedRowIds = [...prevIds]; if (shiftKey && firstRowIndex !== null) { const start = Math.min(firstRowIndex, index); const end = Math.max(firstRowIndex, index); const idsToSelect = filteredAndSortedData.slice(start, end + 1).map((строка: любая) => row.id); newSelectedRowIds.push(...idsToSelect); } Еще если (newSelectedRowIds.includes(rowId)) { const index = newSelectedRowIds.indexOf(rowId); если (индекс > -1) { newSelectedRowIds.splice(индекс, 1); } } еще { setFirstRowIndex(индекс); newSelectedRowIds.push(rowId); } return Array.from(new Set(newSelectedRowIds)); }); }, [setSelectedRowIds, firstRowIndex, filteredAndSortedData], ); const selectedRows = useMemo(() => { return selectedRowIds.map((rowId) => data.find((row) => row.id === rowId)).filter(Boolean); }, [данные, selectedRowIds]); const currentDialogState = useMemo(() => DialogsState[selectedColumn?.accessor], [ диалогиСостояние, selectedColumn?.accessor, ]); useEffect(() => { const handleEditSequence = async (id: string) => { пытаться { const { данные: последовательность } = ждут pssApi.getSequenceById({ параметры: { идентификатор, }, }); если (!последовательность) { возвращаться; } setSequenceName(последовательность?.имя); setStartDate(момент(последовательность?.startDate)); если (последовательность?.scheduledCaster) { setCasterType (последовательность?.scheduledCaster); setOneCasterChecked (истина); } еще { setOneCasterChecked (ложь); } const {data: dataScenario } = await pssApi.getScenarioMaterialList({params: {sequenceScenarioId: id } }); const allSlabs = ExtractAllSlabs (dataScenario); setDataScenario(dataScenario); const newSelectedRowIds: string[] = []; для (пусть я = 0; я; если (идентификатор) { handleEditSequence (идентификатор); } еще { setSequenceName(''); setSelectedRowIds([]); setSelectedRowIdsOld([]); setIsEdition (ложь); setSequenceId (ноль); setStartDate (не определено); setDataScenario (ноль); setOneCasterChecked (ложь); setCasterType (ноль); } }, [маршрут]); const RowRenderer = useMemo( () => ({ индекс строки, Данные ряда, клетки, переключитьRowSelection, выбранныеRowIds, }: { ячейки: React.ReactNode[]; столбцы: ColumnShape; данные строки: любой; индекс строки: число; toggleRowSelection: (rowId: строка, индекс: число,shiftKey: логическое значение) => void; selectedRowIds: строка []; }) => { const isSelected = selectedRowIds.includes(rowData.id); const rowStyle = { BackgroundColor: isSelected? '#cce6ff' : '#fff', FontWeight: isSelected? 'жирный': 'нормальный', дисплей: «гибкий», alignItems: 'растянуть', }; const WrapCells = Cells.map((ячейка: любая, индекс: число) => {ячейка}); возвращаться ( toggleRowSelection(rowData.id, rowIndex, event.shiftKey)}> {wrappedCells} ); }, [], ); const CellRenderer = useMemo( () => ({cellData }: {cellData: строка }) => { константная ячейка = { дисплей: «гибкий», alignItems: 'центр', отступ: '8px', whiteSpace: 'nowrap', курсор: 'указатель', переход: 'background-color 0.2s', }; вернуть {cellData}; }, [], ); const headerCellStyle = { FontWeight: 'жирный', курсор: 'указатель', отступ: '0 4px', alignItems: 'центр', whiteSpace: 'nowrap', }; const Container = styled.div` ширина: 100%; высота: расчет (100vh – 240 пикселей); `; const handleColumnResizeEnd = useCallback( ({столбец, ширина}: {столбец: ColumnShape; ширина: число }) => { const newColumns = [...currentColumns]; const columnsIndex = newColumns.findIndex((col) => col.accessor === columns.dataKey); если (columnIndex !== -1) { newColumns[columnIndex].defaultWidth = ширина; handleData (новые столбцы); } }, [текущиеколонны], ); const openFilterDialog = useCallback( (событие: React.MouseEvent, столбец: ColumnShape) => { событие.stopPropagation(); setSelectedColumn (столбец); если (Object.keys(appliedFilters).length) { const currentFilter = applyFilters[column.accessor]; setCurrentFilterValue (currentFilter? CurrentFilter: undefined); } const rect = event.currentTarget.getBoundingClientRect(); const x = rect.right + 10; const y = rect.bottom + 10; константная ширина диалога = 300; константный диалогВысота = 200; const maxX = window.innerWidth - DialogWidth - 10; const maxY = window.innerHeight - DialogHeight - 10; const диалогX = Math.min(x, maxX); const диалогY = Math.min(y, maxY); setDialogPosition({ x: диалогX, y: диалогY }); setDialogOpen (истина); }, [прикладные фильтры], ); useLayoutEffect(() => { const restreScroll = () => { const ScrollableElement = document.querySelector('[class*=BaseTable__body]'); если (прокручиваемыйЭлемент) { прокруткиElement.scrollTop = прокруткиPositionRef.current; } }; const timeoutId = setTimeout (restoreScroll, 1); возврат () => { ClearTimeout (идентификатор таймаута); }; }, [selectedRowIds]); возвращаться ( {({ ширина, высота }) => ( ( )} > {currentColumns .filter((столбец: любой) => !столбец?.скрытый) .map((столбец: любой, индекс: число) => ( ( openFilterDialog (событие, столбец)} > {column.Header} )} cellRenderer={(реквизит: { данные ячейки: любой; столбцы: ColumnShape[]; столбец: ColumnShape; индекс столбца: число; данные строки: неизвестно; индекс строки: число; контейнер: Стол; }) => } /> ))} )} {isDialogOpen && ( setDialogOpen (ложь)} setFilter={setFilter} позиция = {dialogPosition} setCurrentFilterValue={setCurrentFilterValue} данные={данные} DialogState={currentDialogState || {}} updateDialogState={updateDialogState} onColumnSort={onColumnSort} /> )} {reorderDialogOpen && ( setReorderDialogOpen (ложь)} onUpdateColumns={setCurrentColumns} /> )} ); }; экспортировать React.memo по умолчанию (TableComponent);
Спасибо за ваше время и опыт!
Сейчас я работаю над сложным компонентом таблицы React, который вызывает некоторые проблемы с производительностью и удобством использования. Основная проблема заключается в том, что при выборе строк позиция прокрутки таблицы смещается, что дезориентирует пользователя. Мне бы хотелось услышать ваши идеи и предложения о том, как оптимизировать этот компонент и устранить указанную проблему.
Обзор компонентов:
Компонент таблицы (TableComponent), который я разрабатываю, использует пакет React-base-table. Вот некоторые из его функций и возможностей:
Динамический выбор строк. Пользователи могут выбирать строки простым щелчком мыши или несколько строк с помощью клавиши Shift. Выборки визуально выделяются, а списком выбранных строк можно управлять вне этой таблицы. Ими также можно манипулировать за пределами этой таблицы с помощью компонента SelectedRowsSummary для сохранения или редактирования последовательностей.
Фильтрация. Диалоговое окно фильтрации позволяет пользователям применять фильтры к определенным столбцам. Активные фильтры выделяют заголовки столбцов курсивом.
Изменение порядка столбцов. Изменить порядок столбцов можно в отдельном диалоговом окне.
Сортировка: столбцы можно сортировать, и компонент отслеживает текущие состояния сортировки. . Восстановление состояния. Компонент может восстанавливать свое состояние, включая примененные фильтры и порядок сортировки, из локального хранилища.
Технические проблемы:
Переход позиции прокрутки: при выборе строк позиция прокрутки таблицы неожиданно смещается. Я попытался сохранить положение прокрутки в ссылке, а затем восстановить его, но это непростое решение.
Монтаж и размонтирование. Из-за динамического характера таблицы и способа работы React компоненты часто монтируются и размонтируются. Такое поведение приводит к тому, что ссылка на таблицу иногда не определена при запуске эффекта макета. В качестве обходного пути я напрямую запрашиваю DOM, чтобы получить прокручиваемый элемент, но я знаю, что это не метод React.
Эффективность: текущая структура и логика, особенно с учетом всей памяти и управления состоянием, возможно, не самая эффективная. Я обеспокоен тем, что это может привести к проблемам с производительностью.
Ищу предложения:
Меня особенно интересует информация о:
Как сохранить плавность положения прокрутки после выбора строки.
Как эффективно управлять состоянием, особенно с таким динамическим компонентом.
Существует ли более «React-подобный» способ решения проблем, с которыми я сталкиваюсь, вместо прямого запроса к DOM.
Любые другие общие оптимизации или рекомендации, которые можно применить к этому компоненту.
Весь код соответствующих компонентов:
Таблица
импортировать React, {useState, useEffect, useMemo, useCallback, useRef, useLayoutEffect } из «реагировать»; импортировать таблицу, { AutoResizer, Column, ColumnShape } из «реагировать-базовой таблицы»; импортировать {Уведомление} из '@sms/plasma-ui'; импортировать момент из «момента»; импортировать стили из «styled-comments»; импортировать { pssApi } из '../../services'; импортировать {ReorderColumnsDialog, SelectedRowsSummary, FilterDialog} из './comComponents'; импортировать {isSameSlab, extractAllSlabs, getData, handleData} из './utils'; импортировать 'реагировать-базовую таблицу/styles.css'; импортировать html2canvas из «html2canvas»; const TableComponent = ({ столбцы, данные, мультизначениефильтр, маршрут, }: { столбцы: любой []; данные: любые[]; multiValueFilter: любой; маршрут: любой; }) => { const [isDialogOpen, setDialogOpen] = useState (false); const [selectedColumn, setSelectedColumn] = useState (null); const [currentFilterValue, setCurrentFilterValue] = useState (не определено); const [selectedRowIds, setSelectedRowIds] = useState([]); const [selectedRowIdsOld, setSelectedRowIdsOld] = useState([]); const [firstRowIndex, setFirstRowIndex] = useState (null); const [reorderDialogOpen, setReorderDialogOpen] = useState (false); const [appliedFilters, setAppliedFilters] = useState>({}); const [sortConfig, setSortConfig] = useState (null); const [dialogPosition, setDialogPosition] = useState({x: 0, y: 0 }); const [dialogsState, setDialogsState] = useState>({}); const [showSelectedOnTop, setShowSelectedOnTop] = useState (false); const [sequenceName, setSequenceName] = useState(''); const [sequenceId, setSequenceId] = useState (null); const [startDate, setStartDate] = useState (не определено); const [casterType, setCasterType] = useState (null); const [oneCasterChecked, setOneCasterChecked] = useState (false); const [currentColumns, setCurrentColumns] = useState(() => getData(columns)); const [isEdition, setIsEdition] = useState(false); const [dataScenario, setDataScenario] = useState (null); const ScrollPositionRef = useRef (0); const sortStatesConstructorFunction = () => { return currentColumns.reduce((согл.: любой, столбец: любой) => { если (столбец?.defaultSort) { acc[column.accessor] = columns.defaultSort; } возврат акк; }, {}); }; const [sortStates, setSortStates] = useState>(sortStatesConstructorFunction); const singleSort = (данные: любой[], dataKey: строка, порядок: 'по возрастанию' | 'по убыванию') => { return [...data].sort((a, b) => { const dir = порядок === 'по возрастанию'? 1:-1; if (a[dataKey] > b[dataKey]) вернуть каталог; если (a[dataKey] { setShowSelectedOnTop((prev) => !prev); }, []); const handleClearAllFilters = useCallback(() => { setAppliedFilters({}); setSortConfig (ноль); setSortStates(sortStatesConstructorFunction); if (isEdition && последовательностьId) { localStorage.removeItem(`sequenceTableState_${sequenceId}`); } }, [setAppliedFilters, setSortConfig, isEdition, SequenceId]); const filteredAndSortedData = useMemo(() => { пусть выходные данные = multiValueFilter (данные, applyFilters); если (сортКонфиг) { const {dataKey, заказ} = sortConfig; выходные данные = SingleSort (выходные данные, ключ данных, порядок); } если (showSelectedOnTop) { const selectedItems = []; const unselectedItems = [...outputData]; for (const rowId of selectedRowIds) { const index = unselectedItems.findIndex((item) => item.id === rowId); если (индекс !== -1) { selectedItems.push(unselectedItems[индекс]); unselectedItems.splice(индекс, 1); } } return [...selectedItems, ...unselectedItems]; } вернуть выходные данные; }, [appliedFilters, data, multiValueFilter, sortConfig, selectedRowIds, showSelectedOnTop]); const setFilter = useCallback( ( ColumnAccessor: строка, ценить: | нить | нить[] | { datetime: { startDate: moment.Moment | нулевой; КонечнаяДата: момент.Момент | нулевой } } | неопределенный, ) => { setAppliedFilters((предыдущий) => ({ ...предыдущий, [columnAccessor]: значение, })); }, [setAppliedFilters], ); const onColumnSort = useCallback( ({ столбец, ключ, порядок }: любой) => { пусть dataKey = columns.dataKey ?? столбец.аксессор; setSortStates((предыдущая) => { if (prev[key] === 'desc') { const newState = { ...prev }; удалить newState[ключ]; вернуть новое состояние; } return { ...prev, [ключ]: заказ }; }); setSortConfig({ключ, заказ, dataKey}); }, [setSortStates, setSortConfig], ); const updateDialogState = useCallback( (аксессор: строка, новые значения: любые) => { setDialogsState((предыдущая) => ({ ...предыдущий, [аксессуар]: { ...предыдущая[аксессуар], ...новые значения, }, })); }, [setDialogsState], ); const toggleRowSelection = useCallback( async (rowId: любой, индекс: число, ShiftKey: логическое значение) => { const ScrollableElement = document.querySelector('[class*=BaseTable__body]'); если (прокручиваемыйЭлемент) { ScrollPositionRef.current = прокручиваемыйЭлемент.scrollTop; } setSelectedRowIds((prevIds: любой) => { const newSelectedRowIds = [...prevIds]; if (shiftKey && firstRowIndex !== null) { const start = Math.min(firstRowIndex, index); const end = Math.max(firstRowIndex, index); const idsToSelect = filteredAndSortedData.slice(start, end + 1).map((строка: любая) => row.id); newSelectedRowIds.push(...idsToSelect); } Еще если (newSelectedRowIds.includes(rowId)) { const index = newSelectedRowIds.indexOf(rowId); если (индекс > -1) { newSelectedRowIds.splice(индекс, 1); } } еще { setFirstRowIndex(индекс); newSelectedRowIds.push(rowId); } return Array.from(new Set(newSelectedRowIds)); }); }, [setSelectedRowIds, firstRowIndex, filteredAndSortedData], ); const selectedRows = useMemo(() => { return selectedRowIds.map((rowId) => data.find((row) => row.id === rowId)).filter(Boolean); }, [данные, selectedRowIds]); const currentDialogState = useMemo(() => DialogsState[selectedColumn?.accessor], [ диалогиСостояние, selectedColumn?.accessor, ]); useEffect(() => { const handleEditSequence = async (id: string) => { пытаться { const { данные: последовательность } = ждут pssApi.getSequenceById({ параметры: { идентификатор, }, }); если (!последовательность) { возвращаться; } setSequenceName(последовательность?.имя); setStartDate(момент(последовательность?.startDate)); если (последовательность?.scheduledCaster) { setCasterType (последовательность?.scheduledCaster); setOneCasterChecked (истина); } еще { setOneCasterChecked (ложь); } const {data: dataScenario } = await pssApi.getScenarioMaterialList({params: {sequenceScenarioId: id } }); const allSlabs = ExtractAllSlabs (dataScenario); setDataScenario(dataScenario); const newSelectedRowIds: string[] = []; для (пусть я = 0; я; если (идентификатор) { handleEditSequence (идентификатор); } еще { setSequenceName(''); setSelectedRowIds([]); setSelectedRowIdsOld([]); setIsEdition (ложь); setSequenceId (ноль); setStartDate (не определено); setDataScenario (ноль); setOneCasterChecked (ложь); setCasterType (ноль); } }, [маршрут]); const RowRenderer = useMemo( () => ({ индекс строки, Данные ряда, клетки, переключитьRowSelection, выбранныеRowIds, }: { ячейки: React.ReactNode[]; столбцы: ColumnShape; данные строки: любой; индекс строки: число; toggleRowSelection: (rowId: строка, индекс: число,shiftKey: логическое значение) => void; selectedRowIds: строка []; }) => { const isSelected = selectedRowIds.includes(rowData.id); const rowStyle = { BackgroundColor: isSelected? '#cce6ff' : '#fff', FontWeight: isSelected? 'жирный': 'нормальный', дисплей: «гибкий», alignItems: 'растянуть', }; const WrapCells = Cells.map((ячейка: любая, индекс: число) => {ячейка}); возвращаться ( toggleRowSelection(rowData.id, rowIndex, event.shiftKey)}> {wrappedCells} ); }, [], ); const CellRenderer = useMemo( () => ({cellData }: {cellData: строка }) => { константная ячейка = { дисплей: «гибкий», alignItems: 'центр', отступ: '8px', whiteSpace: 'nowrap', курсор: 'указатель', переход: 'background-color 0.2s', }; вернуть {cellData}; }, [], ); const headerCellStyle = { FontWeight: 'жирный', курсор: 'указатель', отступ: '0 4px', alignItems: 'центр', whiteSpace: 'nowrap', }; const Container = styled.div` ширина: 100%; высота: расчет (100vh – 240 пикселей); `; const handleColumnResizeEnd = useCallback( ({столбец, ширина}: {столбец: ColumnShape; ширина: число }) => { const newColumns = [...currentColumns]; const columnsIndex = newColumns.findIndex((col) => col.accessor === columns.dataKey); если (columnIndex !== -1) { newColumns[columnIndex].defaultWidth = ширина; handleData (новые столбцы); } }, [текущиеколонны], ); const openFilterDialog = useCallback( (событие: React.MouseEvent, столбец: ColumnShape) => { событие.stopPropagation(); setSelectedColumn (столбец); если (Object.keys(appliedFilters).length) { const currentFilter = applyFilters[column.accessor]; setCurrentFilterValue (currentFilter? CurrentFilter: undefined); } const rect = event.currentTarget.getBoundingClientRect(); const x = rect.right + 10; const y = rect.bottom + 10; константная ширина диалога = 300; константный диалогВысота = 200; const maxX = window.innerWidth - DialogWidth - 10; const maxY = window.innerHeight - DialogHeight - 10; const диалогX = Math.min(x, maxX); const диалогY = Math.min(y, maxY); setDialogPosition({ x: диалогX, y: диалогY }); setDialogOpen (истина); }, [прикладные фильтры], ); useLayoutEffect(() => { const restreScroll = () => { const ScrollableElement = document.querySelector('[class*=BaseTable__body]'); если (прокручиваемыйЭлемент) { прокруткиElement.scrollTop = прокруткиPositionRef.current; } }; const timeoutId = setTimeout (restoreScroll, 1); возврат () => { ClearTimeout (идентификатор таймаута); }; }, [selectedRowIds]); возвращаться ( {({ ширина, высота }) => ( ( )} > {currentColumns .filter((столбец: любой) => !столбец?.скрытый) .map((столбец: любой, индекс: число) => ( ( openFilterDialog (событие, столбец)} > {column.Header} )} cellRenderer={(реквизит: { данные ячейки: любой; столбцы: ColumnShape[]; столбец: ColumnShape; индекс столбца: число; данные строки: неизвестно; индекс строки: число; контейнер: Стол; }) => } /> ))} )} {isDialogOpen && ( setDialogOpen (ложь)} setFilter={setFilter} позиция = {dialogPosition} setCurrentFilterValue={setCurrentFilterValue} данные={данные} DialogState={currentDialogState || {}} updateDialogState={updateDialogState} onColumnSort={onColumnSort} /> )} {reorderDialogOpen && ( setReorderDialogOpen (ложь)} onUpdateColumns={setCurrentColumns} /> )} ); }; экспортировать React.memo по умолчанию (TableComponent);
Спасибо за ваше время и опыт!
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение