📋Кейс «Тяжелые списки» (финтех-сервис)
🔹Контекст:
В банковском приложении рендерится большой список операций. При изменении статуса одной транзакции (approve/reject) весь список начинает жутко лагать, а React DevTools показывает 300+ ререндеров.
{transactions.map(tx => (
<TransactionRow
key={tx.id}
transaction={tx}
onApprove={handleApprove}
/>
))}🔹Вопросы для размышления:
● Почему при обновлении только одной транзакции перерисовываются абсолютно все строки списка?
● Как исправить проблему, не меняя архитектуру компонента?
● Когда реально стоит использовать React.memo / useMemo / useCallback? (а когда это только усложнит код?)
Подумали над решением? Тогда смотрите ответ👇
● По умолчанию при изменении стейта родителя React ререндерит все дерево вниз. Заново создаются пропсы для дочерних компонентов. Если handleApprove создается заново (новая ссылка) и/или transaction пересоздается как новый объект, React видит "пропсы изменились", значит все TransactionRow ререндерятся.
● Минимальный фикс — обернуть TransactionRow в React.memo, а handleApprove стабилизировать через useCallback. Также важно обновлять только нужный объект в массиве transactions, чтобы остальные сохранили свои ссылки.
● React.memo стоит использовать при длинных списках и тяжелых компонентах, useCallback при передаче функций вниз, а useMemo, если вычисления дорогие (фильтр/сортировка). Если компонент легкий — мемоизация лишь усложнит код.
🎯Цель данной задачи — проверить понимание причин ререндеров и умение оптимизировать React осознанно, а не "оборачивать всё подряд".
🗣Комментарий эксперта.
Главная ловушка — думать, что “React сам разберется”. Он и разбирается: видит новые ссылки — честно перерисовывает. Многие забывают, что React.memo работает только в связке со стабильными ссылками. Если вы обернули компонент в memo, но передаете в него onApprove={() => doSomething()}, вы просто тратите ресурсы на бесполезную проверку пропсов. Оптимизируйте осознанно: сначала замеряйте профилировщиком, а потом внедряйте мемоизацию.
#Задача_от_эксперта