<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Почему React Compiler пропускает 70% ре-рендеров: грабли с unstable APIs и нативный фикс]]></title><description><![CDATA[<p dir="auto">React Compiler обещает автоматом резать лишние ре-рендеры, но на деле пропускает до 70% случаев. Всё из-за unstable APIs, которые ломают анализ под капотом. Разберём, где собака зарыта, и покажем нативный фикс без флагов и костылей.</p>
<p dir="auto">Это спасёт от загадочных циклов рендеров и утечек производительности. Поймёшь, почему твои memo и useCallback вдруг перестают работать. И главное - как починить без лишних deps и экспериментальных фич.</p>
<h2>Unstable APIs подрывают компиляцию</h2>
<p dir="auto">React Compiler - это babel-плагин, который статически анализирует код и генерит memo по всем правилам. Он смотрит на пропсы, стейт и эффекты, чтобы понять, что можно кэшировать. Но unstable_ хуки вроде unstable_useCache или экспериментальные API из canary-версий React рвут эту логику. Компилятор видит unknown - и просто пропускает компонент, оставляя тебя с классическими ре-рендерами.</p>
<p dir="auto">Представь: ты пихаешь fetch с ?? в try/catch, как в свежем рефакторе SSE на fetch. Компилятор не понимает асинхронку внутри колбэка - и бац, ref для инпута начинает колбаситься в цикле. Или useReducer с мутабельным объектом: анализ ломается на shallow compare, и 70% потенциальных мемоизаций улетают в никуда. Реальные проекты показывают: после апгрейда на Compiler производительность не взлетает, а иногда даже проседает из-за таких слепых зон.</p>
<p dir="auto">Вот типичные грабли:</p>
<ul>
<li><strong>unstable_useCache в эффектах</strong>: Кэш не статичен, компилятор игнорирует весь компонент.</li>
<li><em>Try/catch с nullable операторами (??)</em>: Анализ асинхронных блоков сбивается, пропсы считаются volatile.</li>
<li><strong>Мутации в useReducer</strong>: Shallow diff не проходит, ре-рендеры по полной.</li>
</ul>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Проблема</th>
<th>Почему Compiler пропускает</th>
<th>Процент ре-рендеров</th>
</tr>
</thead>
<tbody>
<tr>
<td>unstable API</td>
<td>Unknown behavior</td>
<td>70%+</td>
</tr>
<tr>
<td>Async в колбэках</td>
<td>Non-deterministic</td>
<td>50%</td>
</tr>
<tr>
<td>Mutable state</td>
<td>Failed static analysis</td>
<td>40%</td>
</tr>
</tbody>
</table>
<h2>Циклы ре-рендеров от ref-колбэков</h2>
<p dir="auto">Ref-колбэки - это классика для инпутов и фокуса, но с Compiler они превращаются в минное поле. Компилятор ожидает чистые функции без сайд-эффектов, а ref callback мутирует DOM напрямую. Если внутри есть unstable deps или динамические значения - анализ стопорится, и компонент ререндерится на каждом тике.</p>
<p dir="auto">Пример из жизни: инпут с onChange, где ref апдейтит value через setState. Родитель меняет пропс - ref колбэк пересоздаётся, Compiler не мемоирует, цикл запущен. Добавь useCallback без правильных deps - и получишь утечку памяти плюс лаг на 100мс. Новички думают, что дело в React.memo, но проблема глубже: статический анализ видит ref как impure.</p>
<p dir="auto">Чеклист для фикса ref-ловушек:</p>
<ul>
<li>Используй <strong>useRef</strong> вместо callback-ref, если возможно - нативно без ре-рендеров.</li>
<li><em>Deps в useCallback</em>: Включи все volatile пропсы, иначе Compiler их пропустит.</li>
<li>Избегай мутаций в ref.current внутри эффектов - компилятор слепнет.</li>
</ul>
<h2>Скрытые грабли в стейт-менеджерах</h2>
<p dir="auto">useState и useReducer кажутся безобидными, но с Compiler они требуют идеальной иммутабельности. Если стейт - объект с nested changes, shallow compare проваливается, и ре-рендеры летят по дереву. Контекст усугубляет: один провайдер дернулся - вся поддерево в огне.</p>
<p dir="auto">В реальных аппах это выглядит так: auth-state с user объектом мутируется где-то в редьюсере. Компилятор не видит deep diff - пропускает мемоизацию. Результат: 70% ре-рендеров в формах и списках. Плюс, если пихаешь let-переменные в контекст - рендеры не растут, но Compiler их не оптимизирует, путая с динамикой.</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Стейт-апдейт</th>
<th>Compiler реакция</th>
<th>Фикс</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mutable object</td>
<td>Skip memo</td>
<td>Immer или spread</td>
</tr>
<tr>
<td>Nested mutation</td>
<td>Full re-render</td>
<td>immer-produce</td>
</tr>
<tr>
<td>Context volatile</td>
<td>Tree-wide</td>
<td>Split providers</td>
</tr>
</tbody>
</table>
<p dir="auto">Ключевые правила:</p>
<ul>
<li><strong>Всегда spread</strong>: {…prev, new: val} - Compiler увидит.</li>
<li><em>useReducer с pure reducers</em>: Без сайд-эффектов.</li>
<li>Разбивай контексты на мелкие - меньше каскадов.</li>
</ul>
<h2>Нативный фикс без флагов и костылей</h2>
<p dir="auto">Забудь про experimental flags и babel-плагины с хаком. Нативный подход - писать код, который Compiler жрёт на ура: чистые функции, immutable patterns, refs для мутабельного. Нет unstable - нет проблем. Это не про мемоизацию везде, а про архитектуру под статический анализ.</p>
<p dir="auto">Суть: refactor стейт на примитивы + refs, убирай async из рендер-пути, split компоненты. В итоге Compiler ловит 90%+ оптимизаций без единого useCallback. Проекты после такого фикса показывают FPS рост на 2x без профайлера.</p>
<p dir="auto">Паттерны для 100% совместимости:</p>
<ul>
<li><strong>Primitive state</strong>: Никаких объектов - строки, числа, массивы с ID.</li>
<li><em>Refs для DOM мутаций</em>: useRef.current.update() без стейта.</li>
<li>Custom hooks с pure returns - Compiler их слопает.</li>
</ul>
<h2>Что Compiler не видит за углом</h2>
<p dir="auto">Автоматическая мемоизация крута, но на 2026 год она слепа к dynamic imports и server components в RSC. Подумать стоит над hybrid подходом: Compiler + ручной профайлер для edge-кейсов. И да, legacy-код с class components вообще игнорируется - рефакторь по частям.</p>
]]></description><link>https://forum.exlends.ru/topic/1990/pochemu-react-compiler-propuskaet-70-re-renderov-grabli-s-unstable-apis-i-nativnyj-fiks</link><generator>RSS for Node</generator><lastBuildDate>Sat, 17 Oct 2026 03:45:21 GMT</lastBuildDate><atom:link href="https://forum.exlends.ru/topic/1990.rss" rel="self" type="application/rss+xml"/><pubDate>Sat, 28 Mar 2026 15:45:06 GMT</pubDate><ttl>60</ttl></channel></rss>