Как избежать лишних перерендеров компонентов в React
Что проверяют
Понимаете ли вы, когда React перерисовывает компонент и что с этим делать. Ключевое тут не список приёмов, а умение сначала измерить, а потом оптимизировать.
Как отвечать
Сначала о причинах. Компонент перерисовывается, когда изменилось его состояние, изменился контекст, на который он подписан, или перерисовался родитель. Последнее и есть источник большинства лишних отрисовок.
Что помогает:
memo: компонент не перерисуется, если пропсы не изменились по поверхностному сравнению;useMemoдля тяжёлых вычислений иuseCallbackдля функций, которые уходят в пропсы мемоизированного ребёнка;- поднять состояние вниз: если часто меняется только счётчик, вынесите его в маленький компонент вместо того, чтобы держать в корне;
childrenкак проп: переданный сверху узел не пересоздаётся при обновлении обёртки;- правильные ключи в списках: индекс массива вместо идентификатора заставляет React переделывать элементы при вставке в середину;
- разделять контекст: один большой контекст обновляет всех подписчиков, даже тех, кому нужна одна редко меняющаяся часть.
Порядок действий важнее приёмов: сначала профилировщик React DevTools, он показывает, что именно перерисовывается и почему, и только потом мемоизация проблемного места.
Где спотыкаются
Обмазывают memo и useCallback всё подряд. Сравнение пропсов и хранение ссылок тоже стоят времени и памяти, а на дешёвых компонентах это чистый убыток.
Ставят memo, но передают объект или функцию, создаваемые в родителе на каждый рендер. Ссылка новая, сравнение не проходит, мемоизация бесполезна.
Путают перерисовку с изменением DOM: React может перерисовать компонент и ничего не поменять в разметке. Дорого второе, а не первое.