Использование конкурентного режима (экспериментально)

Внимание:

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

Большая часть информации на данной странице уже не актуальна и оставлена для истории. Актуальная информация приведена в посте блога React 18 Alpha announcement.

Перед выходом React 18 информация на этой странице будет обновлена.

Установка

Конкурентный режим доступен только в экспериментальных сборках React. Чтобы установить их, выполните:

npm install react@experimental react-dom@experimental

Для экспериментальных сборок нет гарантий семантического версионирования

В любом релизе с версией @experimental функции API могут быть добавлены, изменены или удалены.

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

Вы можете пробовать такие сборки в личных проектах или в ветках, однако мы не рекомендуем использовать их в продакшене. В Facebook мы используем их в продакшене, поскольку можем исправлять ошибки, если что-то сломается. Мы вас предупредили.

Для кого предназначен этот экспериментальный релиз?

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

Мы используем экспериментальный код в продакшене (это работает для нас), несмотря на то, что в нем есть некоторое количество ошибок, недоделанные возможности и пробелы в документации. Нам бы хотелось выявить ошибки в конкурентном режиме, чтобы лучше подготовить его к официальному стабильному релизу в будущем.

Включение конкурентного режима

Обычно, когда мы добавляем новые возможности в React, вы можете сразу же использовать их. Например, фрагменты, контекст и даже хуки были именно такими. Их можно использовать в новом коде не меняя уже существующий.

С конкурентным режимом другая история. В нём изменена сама суть работы React. В противном случае использование новых возможностей было бы невозможно. Именно поэтому они объединены в новый «режим», а не выпускаются по-отдельности.

Вы не можете использовать конкурентный режим для отдельных поддеревьев. Включать конкурентный режим нужно в том же месте, где ранее вы вызывали функцию ReactDOM.render().

Включение конкурентного режима для всего дерева <App />:

import ReactDOM from 'react-dom';

// Раньше вы использовали:
//
// ReactDOM.render(<App />, document.getElementById('root'));
//
// Теперь для перехода в конкурентный режим нужно написать:

ReactDOM.unstable_createRoot(
  document.getElementById('root')
).render(<App />);

Примечание:

Функции API конкурентного режима доступны только в экспериментальных сборках React.

В конкурентном режиме методы жизненного цикла, ранее помеченные как «небезопасные», становятся действительно небезопасными и приводят к ошибкам гораздо чаще, чем в текущих релизах React. Мы не рекомендуем использовать конкурентный режим, пока ваше приложение не будет поддерживать строгий режим.

К чему готовиться?

Если у вас достаточно большое приложение или в нём много сторонних зависимостей, не стоит надеяться на быстрый переход на конкурентный режим. Например, в Facebook мы используем конкурентный режим только на новых сайтах и не планируем задействовать его на старых. Это из-за того, что старые сайты в продакшен-коде используют небезопасные методы жизненного цикла, несовместимые библиотеки сторонних разработчиков и паттерны, которые плохо работают в конкурентном режиме.

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

Этап миграции: блокирующий режим

Для старых проектов путь перехода на конкурентный режим может оказаться достаточно длинным. Поэтому в экспериментальных сборках React мы предусмотрели новый «блокирующий режим». Вы можете попробовать его, заменив createRoot на createBlockingRoot. Блокирующий режим предоставляет сокращённый набор возможностей конкурентного режима. При этом он ближе к тому, как работает React в настоящее время, и может послужить в качестве промежуточного этапа.

Итого:

  • Старый режим: ReactDOM.render(<App />, rootNode). Это режим, в котором React работает в настоящее время. В обозримом будущем мы не планируем избавляться от старого режима, но он не будет поддерживать новые возможности.
  • Блокирующий режим: ReactDOM.createBlockingRoot(rootNode).render(<App />). В настоящее время экспериментальный. Он предназначен в качестве первого этапа миграции приложений, в которых предполагается использовать часть возможностей конкурентного режима.
  • Конкурентный режим: ReactDOM.createRoot(rootNode).render(<App />). В настоящее время экспериментальный. В будущем, после стабилизации, мы намерены сделать его основным режимом React. Данный режим задействует все новые возможности.

Зачем столько режимов?

Мы считаем, что лучше предложить стратегию постепенной миграции, чем вносить огромные серьезные изменения или позволить React стагнировать.

На практике мы ожидаем, что большинство приложений, использующих в настоящее время старый режим, смогут перейти на конкурентный или, как минимум, на блокирующий. Такая фрагментация может создать некоторые проблемы для авторов библиотек, которые будут вынуждены какое-то время поддерживать все режимы. Однако нужно учитывать, что постепенный переход со старого режима помогает решать проблемы, влияющие на основные библиотеки в экосистеме React, например, странное поведение Задержек при чтении DOM и нестабильность пакетного рендеринга. Есть некоторое количество багов, которые невозможно исправить без изменения семантики в старом режиме, но при этом они отсутствуют в блокирующем или конкурентном режимах.

Вы можете рассматривать блокирующий режим как «отказоустойчивую» версию конкурентного режима. В конечном итоге, в долгосрочной перспективе, у нас будет возможность объединить оба режима и перестать рассматривать их как отдельные друг от друга. В настоящее время режимы являются важной частью переходной стратегии. Они дают возможность каждому определять момент перехода на конкурентный режим и обновлять код в удобном для себя темпе.

Сравнение возможностей

Старый режим Блокирующий режим Конкурентный режим
Строковые рефы 🚫** 🚫**
Старый контекст 🚫** 🚫**
findDOMNode 🚫** 🚫**
Задержка
SuspenseList 🚫
Задержка в React на сервере + гидратация 🚫
Последовательная гидратация 🚫
Выборочная гидратация 🚫 🚫
Кооперативная многозадачность 🚫 🚫
Автоматическая группировка при множественном вызове setStates     🚫*
Приоритетный рендеринг 🚫 🚫
Прерываемый предварительный рендеринг 🚫 🚫
useTransition 🚫 🚫
useDeferredValue 🚫 🚫
Периодические задержки типа «Train» 🚫 🚫

*: Старый режим имеет автоматический пакетный рендеринг для обрабатываемых React-событий, но он ограничен одним потоком браузера. Не React-события должны быть обработаны через unstable_batchedUpdates. В блокирующем и конкурентном режимах все вызовы setState группируются для пакетного рендеринга по-умолчанию.

**: Предупреждения в режиме разработки.