- Концепция Concurrent Mode
- Опыт пользователя
- Прерываемый рендеринг
- Преднамеренные последовательности загрузки
- Как включить Concurrent Mode
- Что теперь
Обещание о создании Concurrent Mode (параллельного режима) было дано на конференции ещё в 2018 году. Команда React утверждает, что новая функция поможет решить проблемы с рендерингом - позволит приостановить его, при возникновении необходимости в выполнении более важных задач.
Концепция Concurrent Mode не является новой революционной функцией, но для React она создает несколько приятных новых возможностей. Несмотря на то, что большинство приложений React работают быстро, мы часто сталкиваемся с некоторыми проблемами при медленном рендеринге. Если твое устройство занято отображением исключительно большого списка, оно не сможет отреагировать на другие события до того, как первое не будет завершено.
Концепция Concurrent Mode
Как я уже упоминал во введении, концепция Concurrent Mode не нова. Возьми процессоры в качестве примера. Процессоры получили scheduler (планировщик задач), который расставляет приоритеты для наиболее важных задач, когда ресурс доступен. То же самое касается компилятора JavaScript, но у него есть один поток (single thread) для взаимодействия с пользователем (поток пользовательского интерфейса), который мы должны использовать с умом. Если этот поток «зависает» из-за перегрузки работы, он не можем реагировать на новые события, пока работа не будет завершена. Concurrent Mode хочет предотвратить это, создав несколько «мини-потоков» в основном потоке пользовательского интерфейса, и с помощью своего собственного планировщика он может поддерживать скорость отклика.
Опыт пользователя
Трудно избежать проблемы многократного рендеринга, потому что даже если твоё приложение имеет хорошую производительность, устройство, которое есть у пользователя, может быть недостаточно сильным для его обработки. Факторы, такие как скорость сети и возможности устройства, могут привести к зависанию приложения, даже если ты хорошо справился с throttling
и debouncing.
Есть некоторые события, например, наведение курсора на элементы или ввод в поле ввода, которые хотелось бы, чтобы происходили немедленно. Если твоё устройство занято рендерингом списка, эффект наведения не будет отображаться до того, как он будет выполнять предыдущую задачу. Когда React начинает рендерить, ты не можешь остановить его, пока этот процесс не будет завершен. Concurrent Mode будет фокусироваться на человеческом взаимодействии; простые задачи, такие как наведение и прокрутка, должны выполняться мгновенно, в то время как переход на новые сайты и загрузка новых данных более приемлемы, так как занимают больше времени.
Прерываемый рендеринг
В параллельном режиме рендеринг может быть прерван. Если пользователь инициирует другое более важное событие, он приостанавливает рендеринг и выполняет желаемое задание, прежде чем вернуться к исходному заданию, чтобы его завершить. Степень важности определяется эвристикой, чтобы знать, как расставить приоритеты в этом новом обновлении. Это (надеюсь) сделает приложение более отзывчивым!
Я не думаю, что мы должны полагаться на тот факт, что Concurrent Mode решит все наши проблемы с производительностью. Тем не менее считаю, что он будет хорошим помощником в тяжелых React-приложениях.
Преднамеренные последовательности загрузки
Это обычное действие, когда ты переходишь на новый сайт на своем сайте, и одновременно хочешь получить данные. Но, немного раздражает, когда перенаправляешься на новую страницу без содержимого или когда показывается какой-то индикатор загрузки.Что если React может заставить нас остаться на предыдущей странице немного дольше, чтобы мы могли пропустить состояние загрузки? Делая это, мы убираем тот факт, что у нас нет всех данных, которые нам нужно показать прямо сейчас. Когда пользователь запустил действие, которое приводит к переходу сайта, React может начать создавать новую страницу (в памяти) и подождать, прежде чем обновлять DOM, пока новая страница не будет готова. И, самое главное «старый» сайт всё ещё интерактивен.
Чтобы таки иметь возможность создавать преднамеренные последовательности загрузки, React предлагает новый хук useTransition
:
const [startTransition, isPending] = useTransition({ timeoutMs: 2000 });
Значение startTransition
является функцией, которую можно использовать в состоянии, которое мы намеренно хотим загрузить. isPending
сообщает нам, если переход продолжается! Если ты поместишь запрос данные в функцию startTransition
, то эта функция будет ждать столько времени, сколько прописано в конфигурации. Конфигурация говорит React, как долго ты готов подождать, прежде чем показывать какой-то “вывод” пользователю.
Давай рассмотрим пример, в котором мы используем startTransition
в качестве события onClick
для кнопки, которая должна получать некоторые асинхронные данные при нажатии:
<button
disabled={isPending}
onClick={() => {
startTransition(() => {
fetchSomeData();
})
}}
>
Как включить Concurrent Mode
Параллельный режим ещё не выпущен, но доступен в теге experimental
. Кент К. Доддс написал пост о том, как включить его, но короткая версия выглядит так.
Чтобы получить версию с параллельным режимом, тебе нужно установить эту экспериментальную версию React:
npm install react@experimental react-dom@experimental
# или: yarn add react@experimental react-dom@experimental
Далее, чтобы включить его, тебе просто нужно внести некоторые изменения в свой основной файл и использовать createRoot
из ReactDOM
:
import React from 'react'
import ReactDOM from 'react-dom'
import App from './app'
// До Concurrent Mode:
const rootEl = document.getElementById('root')
ReactDOM.render(<App />, rootEl)
// После Concurrent Mode:
const root = ReactDOM.createRoot(rootEl)
root.render(<App />)
Кроме того, чтобы иметь возможность использовать параллельный режим, настоятельно рекомендуется использовать строгий режим (StrictMode).
Что теперь
Дата стабильной версии Concurrent Mode ещё не была объявлена, но вот страница релизов для React, где ты можешь отслеживать все изменения.
Между тем, ты можешь наслаждаться экспериментальной версией (но, пока не используй её в продакшене).