Ревью: большой список с фильтром
Вопрос
Перед тобой код на ревью. Скажи вслух, что здесь не так - по убыванию важности.
Читай вслух, как на ревью: сначала что делает код, потом что сломано.
function Table({ rows, query }) {
const filtered = rows.filter((r) => r.name.toLowerCase().includes(query.toLowerCase()));
const sorted = filtered.sort((a, b) => a.name.localeCompare(b.name));
return (
<tbody>
{sorted.map((row) => (
<Row key={row.id} row={row} onClick={() => open(row.id)} />
))}
</tbody>
);
}
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
sort мутирует filtered - а при пустом query это тот же массив, что rows: мутация пропсов
toLowerCase от query вычисляется на каждой строке - вынести из цикла
фильтрация и сортировка на каждом рендере - нужен useMemo при больших объёмах
новая стрелка onClick на каждую строку убивает мемоизацию Row
нет виртуализации для тысяч строк
localeCompare без указания локали и без кэшированного Intl.Collator
Что могут спросить следом
- Как вы поймёте, что useMemo здесь действительно нужен?
- Чем плох localeCompare в цикле?
Разбор
Мутация пропсов. filter возвращает новый массив - но только если что-то отфильтровал.
При пустом query это по-прежнему новый массив, а вот sort мутирует его на месте;
хуже, если бы фильтра не было вовсе. Правильный тон на ревью: sort мутирует, поэтому
[...filtered].sort(...) или toSorted.
Лишняя работа в цикле. query.toLowerCase() пересчитывается для каждой строки -
вынести наружу.
Каждый рендер. Фильтрация и сортировка выполняются заново даже при изменении
не связанного состояния; на тысячах строк это заметно. useMemo по [rows, query].
Мемоизация ломается. Новая стрелка onClick - новый проп на каждый рендер, Row
в memo бесполезен. Передавать row.id и один стабильный обработчик.
Масштаб. Больше пары тысяч строк - виртуализация.
Тонкое: localeCompare без локали работает по настройкам среды и медленный -
для сортировки лучше один Intl.Collator снаружи.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.