Concurrent rendering

Concurrent rendering в React 18 формирует модель выполнения, при которой рендер компонента становится прерываемым, а обновления могут быть приоритизированы. В этой модели UI перестаёт быть строго синхронным процессом, а переходы между состояниями становятся управляемыми через планировщик React. TanStack Query интегрируется в эту модель на уровне управления асинхронным состоянием, обеспечивая согласованность данных при возможных прерываниях рендера, повторных попытках и параллельных запросах.

Модель конкурентного рендеринга React

Основой является возможность React приостанавливать рендеринг дерева компонентов, откладывать менее приоритетные обновления и возобновлять их позже. Это создаёт условия, при которых один и тот же компонент может:

  • начать рендер с одними данными,
  • приостановиться на этапе получения асинхронного результата,
  • возобновиться уже с обновлённым состоянием кеша.

Важным следствием становится необходимость устойчивого источника данных, не зависящего от жизненного цикла конкретного рендера. Эту роль в экосистеме выполняет cache TanStack Query.

Кэш как синхронизационная точка

TanStack Query строит модель вокруг глобального кэша запросов, где каждый queryKey идентифицирует независимое состояние данных. В условиях concurrent rendering кэш выполняет функцию стабилизатора между прерываемыми рендерами.

Ключевые свойства:

  • данные в кэше существуют вне React-рендера,
  • несколько параллельных рендеров используют одну и ту же ссылку на данные,
  • обновления кэша приводят к согласованному пересозданию UI.

Это устраняет проблему «разорванного состояния», когда разные части дерева видят разные версии данных.

Дедупликация запросов при параллельных рендерах

Concurrent rendering усиливает вероятность одновременного запроса одних и тех же данных из нескольких компонентов. TanStack Query применяет дедупликацию на уровне queryKey.

Поведение:

  • при первом запуске запроса создаётся единственный запрос в flight,
  • последующие подписки используют уже существующий промис,
  • результат распределяется между всеми подписчиками.

Это особенно важно при одновременном монтировании нескольких веток дерева в режиме concurrent mode, когда React может повторно инициировать рендер до завершения предыдущего.

Приоритизация обновлений и stale-while-revalidate

Concurrent rendering тесно связан с концепцией приоритетов. TanStack Query использует stale-while-revalidate модель:

  • данные из кэша могут быть мгновенно возвращены как «устаревшие»,
  • в фоне запускается рефетч,
  • UI обновляется при поступлении новых данных.

В условиях concurrent rendering это снижает блокировку интерфейса, позволяя React завершать низкоприоритетные обновления с уже доступным состоянием.

Параметры, влияющие на поведение:

  • staleTime — определяет окно актуальности данных,
  • gcTime — управляет временем жизни кэша,
  • refetchOnMount и refetchOnWindowFocus — инициируют фоновые обновления.

Suspense и приостановка рендера

Интеграция с Suspense является ключевым механизмом взаимодействия с concurrent rendering. При включённом suspense режиме TanStack Query может приостанавливать рендер компонента до получения данных.

Поведение:

  • при отсутствии данных query «бросает» промис,
  • React приостанавливает текущую ветку,
  • fallback UI отображается до завершения запроса.

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

Transition API и управление приоритетами запросов

React transitions (startTransition) позволяют помечать обновления как низкоприоритетные. TanStack Query учитывает этот контекст при запуске мутаций и рефетчей.

Сценарий:

  • пользователь инициирует изменение фильтра,
  • обновление состояния оборачивается в transition,
  • query refetch не блокирует основной ввод,
  • UI сохраняет отзывчивость даже при сетевых задержках.

Это особенно важно при больших списках данных, где изменение queryKey приводит к повторному запросу.

Консистентность данных при прерывании рендера

Concurrent rendering допускает повторное выполнение render-функции до её коммита. Без внешнего кэша это привело бы к гонкам состояния. TanStack Query решает проблему через стабильные ссылки на данные.

Механизм:

  • query возвращает ссылку на объект из кэша,
  • промежуточные состояния (loading, fetching) синхронизируются отдельно,
  • финальный commit всегда использует актуальный snapshot кэша.

Это предотвращает ситуацию, при которой UI «перепрыгивает» между версиями данных.

Отмена запросов и AbortController

При конкурентном рендеринге возможны сценарии, когда запрос становится нерелевантным до завершения. TanStack Query использует AbortController для отмены:

  • смена queryKey инициирует отмену предыдущего запроса,
  • React unmount в concurrent режиме может прервать запрос,
  • только последний актуальный запрос влияет на кэш.

Это снижает нагрузку на сеть и предотвращает race conditions.

Prefetching и подготовка данных

PrefetchQuery играет важную роль в concurrent rendering, позволяя подготовить данные до того, как компонент будет смонтирован.

Особенности:

  • данные помещаются в кэш заранее,
  • при монтировании компонент не входит в loading state,
  • React может завершить рендер без приостановок.

В concurrent режиме это уменьшает вероятность fallback-рендеров и повышает плавность переходов.

Hydration и серверный рендеринг

При использовании SSR или hydration TanStack Query сохраняет согласованность между серверным и клиентским состоянием.

Процесс:

  • сервер заполняет query cache,
  • сериализованный кэш передаётся на клиент,
  • hydration восстанавливает состояние без повторного запроса.

В concurrent rendering это снижает количество «лишних» suspend-приостановок при первом рендере.

Параллельные запросы через useQueries

Concurrent rendering усиливает необходимость группового управления запросами. useQueries позволяет запускать набор запросов параллельно с единым управлением состоянием.

Особенности:

  • каждый query работает независимо,
  • общий рендер может быть приостановлен при suspense,
  • кэш предотвращает дублирование сетевых операций.

Это особенно важно при композиции сложных экранов, где данные приходят из нескольких источников.

Стабильность UI при множественных обновлениях

Concurrent rendering может приводить к частым пересборкам дерева. TanStack Query стабилизирует UI через:

  • структурированный кэш,
  • автоматическое объединение обновлений,
  • подписочную модель обновления компонентов.

Результатом становится предсказуемая реакция интерфейса на поток асинхронных событий без визуальных разрывов.

Взаимодействие с фокусом окна и refetch

В concurrent режиме события фокуса окна могут совпадать с активными рендерами. TanStack Query учитывает это через отложенные refetch-запросы.

Поведение:

  • refetchOnWindowFocus может быть приоритизирован,
  • текущие low-priority transitions не блокируются,
  • кэш обновляется без нарушения текущего commit.

Это предотвращает конфликт между пользовательской активностью и системными обновлениями данных.

Оптимизация повторных рендеров

Concurrent rendering усиливает чувствительность к лишним обновлениям. TanStack Query минимизирует их через:

  • структурное сравнение queryKey,
  • мемоизацию результата select,
  • батчинг обновлений состояния.

Это уменьшает количество повторных commit-фаз React и снижает вероятность перегрузки render pipeline.

Согласование состояния между компонентами

При concurrent rendering несколько компонентов могут одновременно подписываться на один query. TanStack Query обеспечивает единый источник истины:

  • изменения кэша мгновенно транслируются всем подписчикам,
  • нет необходимости в prop drilling,
  • отсутствует дублирование локального состояния.

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

Итоговая модель взаимодействия

Concurrent rendering и TanStack Query формируют связку, в которой асинхронное состояние отделено от жизненного цикла рендера, а UI строится поверх устойчивого кэша с поддержкой приоритетов, отмены запросов и фонового обновления.