TGViewer
Антон Непша.js Антон Непша.js @nepshajs · 2.91K subscribers
Post #79 2.1K
Утечки памяти в React

Недавно наткнулся на статью о том, как хук useCallback может привести к утечкам памяти в React-приложении.

Оригинал статьи здесь. В статье автор демонстрирует, как при использовании нескольких useCallback в одном компоненте может сложиться ситуация, при которой сборщик мусора JavaScript не сможет избавиться от предыдущих контекстов этих useCallback-ов. И данные в этих контекстах будут накапливаться и накапливаться, требуя всё больше и больше памяти.

В этом даже можно убедиться самостоятельно, если воспроизвести пример из статьи у себя локально и заглянуть во вкладку Memory в девтулзах Chrome.

Чтобы избежать утечки, автор статьи советует:

1) Избегать использования слишком больших и сложных компонентов;

2) Выносить логику в кастомные хуки;

3) С осторожностью использовать useMemo и useCallback. И только если замечаете проблемы с производительностью при отрисовке;

4) Хранить тяжелые объекты в useRef. И очищать их вручную, если необходимо.


Но о чём в статье не говорится, так это о том, что React Compiler тоже решает эту проблему))

Допустим, внутри нашего React-компонента будет вот такая строчка, как в статье:
const bigData = new BigObject();

В привычном нам React эта переменная будет создаваться заново при каждом рендере. И да, есть вероятность того, что каждый раз эта переменная будет замыкаться в контекстах разных useCallback.

Но если прогнать через Compiler весь код из статьи, то объявление BigObject там будет выглядеть так:
const $ = _c(22);
let t0;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t0 = new BigObject();
$[1] = t0;
} else {
t0 = $[1];
}
const bigData = t0;

Сначала компайлер создаёт массив $ из такого количества Symbol.for('react.memo_cache_sentinel'), которое ему нужно для того, чтобы запомнить все данные из компонента. В случае с примером из статьи, понадобился массив из 22 штук таких Symbol.

А когда компайлер доходит до const bigData в нашем коде, то он либо выполняет new BigObject() и записывает результат в $[1] (если он убедился, что внутри $[1] находится его этот Symbol), либо забирает этот результат из $[1], если там что-то есть, и присваевает нашей переменной тот результат, который он сохранил себе в $[1] на предыдущем рендере.

И примерно по такому же принципу React Compiler запоминает вообще всё.

И да, можете проверить в Memory, накапливаться там ничего не будет.

P.S. А ещё есть React Compiler Playground, где можно посмотреть, во что он превращает ваш код.

P.P.S. А вот тут можно посмотреть, как на самом деле создаётся этот массив $ для мемоизации данных в React Compiler. Вы удивитесь))
  • 🔥 27
  • 👍 9
  • ❤ 3
  • 🤔 1
More from @nepshajs
  1. Sep 30, 2026👨‍💻 Фронтенд с AI: что можно делегировать агентам 5 октября, стартует конференция Podlod…
  2. Jul 30, 2026Моё хобби — менять названия полей в тулах и смотреть, как это влияет на качество заполнени…
  3. Jul 20, 2026Расширил свой недавний доклад про работу с GigaChat API и расскажу его 25 июля на Технохаб…
  4. Jul 17, 2026Никогда ещё не уходил с митапа под таким сильным впечатлением, как вчера после JS x AI con…
  5. Jul 15, 2026Агентские фреймворки больше не нужны Мне стали часто попадаться видео автора Jake Van Clie…
  6. Jul 10, 2026JS x AI митап в Сбер.Среде Я тут недавно осознал, что я уже два с половиной года работаю с…
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 →