реагировать-сброс фильтра сортировки строк таблицы при изменении данных

#reactjs #redux #react-hooks #react-table

Вопрос:

Я пытаюсь отсортировать данные в таблице реакций, но по мере поступления новых данных сортировка аннулируется. Компонент, содержащий таблицу, получает свои данные из реквизита. Сами эти данные поступают из redux, который каждые 15 секунд обновляется последними данными с сервера (где они часто меняются).

Что бы я хотел, так это отсортировать данные, и чтобы эти типы оставались на месте по мере/при изменении данных. На самом деле происходит то, что я сортирую таблицу по заголовку столбца, а затем, когда данные меняются, сортировка удаляется.

Я пытался:

Сортировочные работы: введите описание изображения здесь

но становится таковым, как только меняются данные: введите описание изображения здесь

Я хотел бы сохранить фильтр сортировки, чтобы по мере поступления новых данных (те же 99% времени, но в 1% случаев значение столбца отличается или появляется новая строка) они сортировались с помощью примененного фильтра сортировки.

Вот упрощенный пример моего кода (настолько маленький, насколько я мог его сделать):

 import * as React from 'react'
import { useTable, Column, useSortBy } from 'react-table'
import * as SharedTypes from '@shared/declarations'

interface Props {
    serverData: SharedTypes.API.MarketBotSummary[]
}

export const TableTest: React.StatelessComponent<Props> = ({ serverData }: Props) => {

    const [localData, setLocalData] = React.useState<SharedTypes.API.MarketBotSummary[]>(serverData)
    const skipPageResetRef = React.useRef<boolean>(false)

    React.useEffect(() => {
        skipPageResetRef.current = true
        setLocalData(serverData)
        console.log('data changed', serverData)
    }, [serverData])

    React.useEffect(() => {
        // After the table has updated, always remove the flag   
        skipPageResetRef.current = false     
    })


    const Table = ({ columns, data }: { columns: Column<SharedTypes.API.MarketBotSummary>[], data: SharedTypes.API.MarketBotSummary[]}) => {
        // Use the state and functions returned from useTable to build your UI
        const {
          getTableProps,
          getTableBodyProps,
          headerGroups,
          rows,
          prepareRow,
          // @ts-ignore
          state: { sortBy }
        } = useTable(
            {
                columns,
                data,
                // @ts-ignore
                // autoResetSortBy: false,
                // autoResetFilters: false,
                autoResetPage: !skipPageResetRef.current,
                autoResetExpanded: !skipPageResetRef.current,
                autoResetGroupBy: !skipPageResetRef.current,
                autoResetSelectedRows: !skipPageResetRef.current,
                autoResetSortBy: !skipPageResetRef.current,
                autoResetFilters: !skipPageResetRef.current,
                autoResetRowState: !skipPageResetRef.current,
            },
            useSortBy
        )

        // Render the UI for your table
        return (
            <>
                <table {...getTableProps()} className="ui celled very compact structured table">
                    <thead>
                    {
                        // @ts-ignore
                        headerGroups.map(headerGroup => (
                        <tr {...headerGroup.getHeaderGroupProps()}>
                        {
                            // @ts-ignore
                            headerGroup.headers.map(column => (
                            <th {
                                    // @ts-ignore
                                    ...column.getHeaderProps(column.getSortByToggleProps())
                                }>
                                {column.render('Header')}
                                <span>
                                    {
                                        // @ts-ignore
                                        column.isSorted ? column.isSortedDesc ? ' 🔽' : ' 🔼' : ''
                                    }
                                </span>
                            </th>
                        ))}
                        </tr>
                    ))}
                    </thead>
                    <tbody {...getTableBodyProps()}>
                    {
                        // @ts-ignore
                        rows.map((row) => {
                            prepareRow(row)
                            
                            return (
                                <tr {...row.getRowProps()}>
                                    {row.cells.map(
                                        // @ts-ignore
                                        cell => <td {...cell.getCellProps({ className: cell.column?.className?.(cell.value, row.original) })}>
                                            {cell.render('Cell')}
                                        </td>
                                        )}
                                </tr>
                            )
                        })}
                    </tbody>
                </table>
                <pre>
                    <code>
                        {JSON.stringify(
                            {
                                sortBy,
                            },
                            null,
                            2
                        )}
                    </code>
                </pre>
            </>
        )
    }
    
    
    const columns = React.useMemo(
        () => [
          {
            Header: 'Data',
            columns: [
                {
                  Header: 'Quote',
                  accessor: 'quote',
                },
                {
                    Header: 'Symbol',
                    accessor: 'symbol',
                },
                {
                    Header: 'Mode',
                    accessor: 'status',                 
                },
                {
                    Header: 'direction',
                    accessor: 'tradeDirection',
                },
            ],
          },
        ],
        []
    )

    const data = React.useMemo(
        () => localData,
        [localData]
    )


    return (
        <Table columns={columns} data={data} />
    )
}

export default TableTest
 

Ответ №1:

Не объявляйте компоненты React внутри других компонентов React. Каждый раз, когда функциональный компонент React повторно отправляет, он воссоздает все , что объявлено в теле его функции, сохраняя при этом ссылки на запоминаемые переменные, поступающие из различных крючков useState , useCallback useMemo и т. Д.

Когда вы объявляете компонент внутри тела другого компонента, вы получаете новый компонент при каждом рендеринге, который не сохранит никакого внутреннего состояния, которое у него было при предыдущем рендеринге. Следовательно, ваши параметры пользовательского интерфейса удаляются.

Объявите Table в отдельном файле и импортируйте его в TableTest . В качестве альтернативы, просто переместите все внутри Table в тело TableTest .

Я бы также избавился от обоих ваших useMemo крючков, так как они ничего не достигают. В первом случае, если у вас есть статический массив/объект, просто объявите его вне области действия компонента, в то время как во втором случае localData он уже эффективно запоминается крючком состояния.

Комментарии:

1. Спасибо, это направило меня в правильном направлении.