TGViewer
ТОП - Тёма о программировани ТОП - Тёма о программировани @temaprog · 2.81K subscribers
Post #144 1.46K
Здарова, работяги!

Потихоньку продолжаю дописывать посты из заметок. В прошлый раз — элементы и файберы, то есть где React держит работу. Теперь — что он с ней делает, когда прилетает обновление. И почему я больше не сужу по счётчику ререндеров, хотя четыре года назад сам учил их считать.

Обновление идёт в две фазы

Render-фаза: React идёт по файберам, зовёт функции компонентов и сверяет свежие элементы с прошлыми. Весь код из тела компонента крутится здесь, чистый JS. Commit-фаза: разница применяется к DOM, тут же бегут useLayoutEffect. Разницы нет — DOM не трогается.

У браузера свой рендер — раскладка и пиксели, и он нужен, только если коммит реально тронул DOM.

Отсюда тезис: вызов функции копеечный, дорого то, что в её теле.

Пример


function Search({ products }) {
const [query, setQuery] = useState('');

return <>
<input value={query} onChange={e => setQuery(e.target.value)} />
<Results products={products} query={query} />
</>;
}

function Results({ products, query }) {
console.count('Results render');

const rows = rankProducts(products, query); // тяжёлый расчёт
return <Table rows={rows} />;
}


Вводим текст, счётчик растёт. Легко решить: Results ререндерится слишком часто, срочно в memo.

Но memo здесь даже не поможет: query меняется с каждым символом, а с ним и пропсы Results.

Счётчик отвечает не на тот вопрос

Консоль ответила на один вопрос: сколько раз React вызвал функцию. Сколько занял каждый вызов, дошёл ли результат до DOM, из-за React ли вообще тормозит — этого в ней нет.

Один вызов функции не равен одному изменению экрана. Под <StrictMode> в dev счётчик удваивается сам по себе. С транзишенами (`startTransition`, `useDeferredValue`) React может прервать или выбросить начатый проход: лог остался, результата нет. В примере их нет — ввод срочный и рендерится синхронно.

Бывает и наоборот: Results вызвался один раз, но rankProducts занял столько, что ввод стал дёрганым. По счётчику эти случаи не различить.

При этом счётчик не бесполезен: «рендерится ли оно вообще без нужды» он показывает за пять секунд. Молчит про то, сколько это стоит.

Что я измеряю вместо этого

Открываю Performance в Chrome, запись, один символ в поле, стоп после обновления таблицы. Трейс ровно того сценария, который тормозит.

На dev-сборке React 19.2+ там сами появляются React Performance tracks, без расширения. Scheduler показывает, срочное обновление или фоновое, и сколько заняли Render, Commit и эффекты; Components — сколько заняли конкретные компоненты и их эффекты. Рядом — обычный JS, layout и paint браузера.

На React до 19.2 — вкладка Profiler в React DevTools: flamegraph по коммитам плюс настройка «Record why each component rendered».

На моём демо к посту один символ — это «+2» в консоли и около четверти секунды на каждый вызов Results на треке. Первое ни о чём, второе — уже диагноз.

Что делать дальше, трек тоже подсказывает:

— широкий Render в Results, а пропсы реально поменялись: memo не спасёт, лечу сам расчёт;
— React отработал быстро, а дальше тянутся layout и paint: ререндеры ни при чём, смотрю, что коммит сделал с DOM;
Results дёргается часто, но копейками: оставляю в покое.

Где это ломается

Dev-сборка медленнее боевой: проверки, двойной рендер Strict Mode, инструментация. Трейс тут ищет подозрительное место, а не точные цифры — за ними в профилировочную сборку.

И трейс — про одно взаимодействие. Копеечный рендер на каждый скролл в нём выглядит невинно, а в сумме уже нет. Если поддерево от изменившегося стейта не зависит, его render лучше не запускать вовсе — это про структуру дерева и colocation, следующий пост.

Резюме

— render — чистый JS, DOM меняется в коммите, браузер рисует, только если коммит что-то тронул;
— количество вызовов не показывает задержку: вызов копеечный, дорого то, что внутри;
— сначала записать одно тормозящее взаимодействие и найти дорогой этап, потом оптимизировать;
— счётчик остаётся для вопроса «рендерится ли вообще» — с него начнётся пост про colocation.
  • 🔥 10
  • ❤ 4
  • 👍 3
  • 🤔 1
More from @temaprog
  1. Sep 15, 2026Здарова, работяги! Кто собирается на Avito.Tech.Conf 26 сентября? Я уже рассказывал про ко…
  2. Sep 14, 2026Зачем ты пишешь? Здарова, работяги! Помню, как все только начинали активно использовать аг…
  3. Sep 4, 2026Здарова, работяги! Приезжает коробка. Внутри бейдж на Avito.Tech.Conf и часы «Ракета».😳 И…
  4. Aug 26, 2026Здарова, работяги! Совсем скоро осень, а значит, начинается сезон конференций. Про Avito.T…
  5. Aug 18, 2026Здарова, работяги! Сейчас я много думаю про AI-native команды и внедрение ИИ в разработку.…
  6. Jun 20, 2026стартуем
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →