Динамическое генерирование таблицы на React [как оптимизировать одновременную фильтрацию и поиск?]

Добрый день, форум, и, в частности, @dmitry

У меня есть вот такая таблица (React):

Количество колонок и строк может быть любым. Тип данных в каждой колонке тоже.
У каждой колонки есть кнопка “Сортировать” и поле для ввода фильтра.
При нажатии на кнопку “Сортировать” мы сортируем таблицу по выбранному столбцу и сбрасываем предыдущий фильтр.
При вводе текста в любое из полей для сортировки мы фильтруем таблицу по значению. Фильтров может быть несколько.
Конечно же, мы хотим, чтобы все было производительно, поэтому мы не хотим заново сортировать всю таблицу, если поменялся только фильтр и, соответственно, мы не хотим заново фильтровать, если мы просто сортируем по другому столбцу.

Что уже есть:

const App = () => {
	// таблица приходит с header и body отдельно
    const { columns, rows } = tableData;
    const [ currentSortField, setCurrentSort ] = useState('id');

    // getSortingFunction - вынимает мемоизированную функцию сортировки по названию поля
    const body = rows
        .sort(getSortingFunction(currentSortField));

    return <>
        <Table
            setSort={setCurrentSort}
            header={columns}
            body={body}
        />
    </>
};

Как прикрутить сюда фильтрацию, чтобы не делать ререндер на каждый чих?
Из библиотек есть lodash, больше ничего использовать нельзя (редаксы всякие и прочее)

Думаю проще отдать это на откуп реакту. Задать каждому ряду уникальный key и пусть сам реакт оптимизирует рендер. Для key использовать не индекс в массиве, а что-то уникальное среди значений элемента. Если такого нет - то сгенерировать и использовать uuid.

Учитывая мой коммент выше - ничего более чем filter -> sort не нужно.

const body = rows
        .filter(...)
        .sort(getSortingFunction(currentSortField));

Еще есть библиотка на хуках для решения как раз той задачи что у тебя. Может она подойдет в твоем случае: react-table - npm

Да, это очевидное решение, но меня беспокоит, что и фильтрация и сортировка будут отрабатывать каждый раз, несмотря на то, что поменялся только кто-то один из них.

Понимаю о чем ты идеологически. На практике скорость работы фильтра+сортировки будет очень очень быстрой. И стоимость сложности кода чтобы сделать их независимыми (придется вносить и менеджерить состояние в котором будет хранится знание о том есть ли фильтр и есть ли сортировка) не покроет преимущества производительности.

Окей, а если подходить к задаче не с практической стороны, а “потому что могу”? Как это решается?

Давай подумаем. Решения у меня в голове нет.

Пусть последовательность действий пользователя будет описана такой нотацией: filter, filter -> sort, sort -> sort итд.

Особых проблем реализовать filter -> sort -> sort нет. Тут каждый sort должен знать о результате последнего filter. sort -> filter -> filter - тут каждый filter работает с результатом sort. Обратим внимание что у нас появляется. состояние - где-то нужно хранить результат одной из предыдущих операций (цена - память, но мы оптимизируем производительность).

А вот случаи filter -> sort -> filter более интересные. Второму filter нельзя работать с результатами sort ибо результаты sort базируются на уже неактуальных результатах предыдущего filter. Значит нужно вызвать sort для оригинальных данных и потом применить к ним filter.

Из этого всего видно что есть некоторые последовательности операций где можно использовать результаты предыдущей операции для последующй. Но есть и такие где результаты предыдущей операции не используются и нужно считать заново.


Дальше углубляться не буду. Но план такой: получается нужно моделировать ситуацию через то какие были операции и каковы их результаты. А потом еще вывести алгоритм при каких последовательностях можно использовать результат одной из предыдущих операций. При этом нужно прикинуть какие преимущества/недостатки будут в реальности применения этой стратегии.

Да, собственно, на этом я и застрял. Окей, спасибо, и хороших выходных!