useTransition¶
useTransition
- это хук React, который позволяет обновлять состояние без блокировки пользовательского интерфейса.
1 |
|
Описание¶
useTransition()
¶
Вызовите useTransition
на верхнем уровне вашего компонента, чтобы пометить некоторые обновления состояния как переходы.
1 2 3 4 5 6 |
|
Параметры¶
useTransition
не принимает никаких параметров.
Возвращаемое значение¶
useTransition
возвращает массив, содержащий ровно два элемента:
- Флаг
isPending
, который сообщает, есть ли ожидающий переход. - Функция
startTransition
, позволяющая пометить обновление состояния как переход.
Функция startTransition
¶
Функция startTransition
, возвращаемая useTransition
, позволяет пометить обновление состояния как переход.
1 2 3 4 5 6 7 8 9 10 11 |
|
Параметры¶
scope
: Функция, которая обновляет некоторое состояние, вызывая одну или несколько функцийset
. React немедленно вызываетscope
без параметров и помечает все обновления состояния, запланированные синхронно во время вызова функцииscope
, как переходы. Они будут неблокирующими и не будут отображать нежелательные индикаторы загрузки.
Возвращаемое значение¶
startTransition
ничего не возвращает.
Ограничения¶
-
useTransition
- это хук, поэтому его можно вызывать только внутри компонентов или пользовательских хуков. Если вам нужно запустить переход в другом месте (например, из библиотеки данных), вызовите вместо этого отдельныйstartTransition
. -
Вы можете обернуть обновление в переход, только если у вас есть доступ к функции
set
этого состояния. Если вы хотите запустить переход в ответ на какой-то пропс или пользовательское значение Hook, попробуйте вместо этого использоватьuseDeferredValue
. -
Функция, которую вы передаете в
startTransition
, должна быть синхронной. React немедленно выполняет эту функцию, помечая все обновления состояния, которые происходят во время ее выполнения, как переходы. Если вы попытаетесь выполнить дополнительные обновления состояния позже (например, во время таймаута), они не будут помечены как переходы. -
Обновление состояния, помеченное как переход, будет прерываться другими обновлениями состояния. Например, если вы обновите компонент графика внутри перехода, а затем начнете вводить текст в поле ввода, когда график находится в середине повторного рендеринга, React перезапустит работу по рендерингу компонента графика после обработки обновления ввода.
-
Обновления переходов нельзя использовать для управления текстовыми вводами.
-
При наличии нескольких текущих переходов React в настоящее время собирает их вместе. Это ограничение, которое, вероятно, будет устранено в будущем выпуске.
Использование¶
Пометка обновления состояния как неблокирующего перехода¶
Вызовите useTransition
на верхнем уровне вашего компонента, чтобы пометить обновление состояния как неблокирующий переход.
1 2 3 4 5 6 |
|
useTransition
возвращает массив, содержащий ровно два элемента:
- Флаг
isPending
, который сообщает, есть ли ожидающий переход. startTransition
функция, которая позволяет отметить обновление состояния как переход.
Вы можете пометить обновление состояния как переход следующим образом:
1 2 3 4 5 6 7 8 9 10 11 |
|
Переходы позволяют сохранить отзывчивость обновлений пользовательского интерфейса даже на медленных устройствах.
С помощью перехода пользовательский интерфейс остается отзывчивым в середине повторного рендеринга. Например, если пользователь нажал на вкладку, но затем передумал и нажал на другую вкладку, он может сделать это, не дожидаясь окончания первого повторного рендеринга.
Разница между useTransition и обычным обновлением состояния¶
1. Обновление текущей вкладки в переходе
В этом примере вкладка "Posts" искусственно замедлена, так что на ее отображение уходит не менее секунды.
Нажмите "Posts", а затем сразу же нажмите "Contact". Обратите внимание, что это прерывает медленное отображение "Posts". Вкладка "Контакт" отображается немедленно. Поскольку это обновление состояния отмечено как переход, медленный повторный рендеринг не привел к зависанию пользовательского интерфейса.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
1 2 3 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
1 2 3 4 5 6 7 8 9 10 11 |
|
2. Обновление текущей вкладки без перехода
В этом примере вкладка "Posts" также искусственно замедляется, так что на ее отображение уходит не менее секунды. В отличие от предыдущего примера, это обновление состояния не является переходом.
Нажмите "Сообщения", а затем сразу же нажмите "Контакт". Обратите внимание, что приложение замирает во время рендеринга замедленной вкладки, а пользовательский интерфейс становится неотзывчивым. Это обновление состояния не является переходом, поэтому медленный повторный рендеринг заморозил пользовательский интерфейс.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
1 2 3 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
1 2 3 4 5 6 7 8 9 10 11 |
|
Обновление родительского компонента в переходе¶
Вы можете обновить состояние родительского компонента и из вызова useTransition
. Например, этот компонент TabButton
обернул свою логику onClick
в переход:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Поскольку родительский компонент обновляет свое состояние внутри обработчика события onClick
, это обновление состояния помечается как переход. Вот почему, как в предыдущем примере, вы можете щелкнуть на "Posts", а затем сразу же щелкнуть на "Contact". Обновление выбранной вкладки помечается как переход, поэтому оно не блокирует взаимодействие с пользователем.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
1 2 3 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
1 2 3 4 5 6 7 8 9 10 11 |
|
Отображение ожидающего визуального состояния во время перехода¶
Вы можете использовать булево значение isPending
, возвращаемое useTransition
, чтобы указать пользователю, что переход находится в процессе. Например, кнопка табуляции может иметь специальное визуальное состояние "в ожидании":
1 2 3 4 5 6 7 8 |
|
Обратите внимание, что нажатие кнопки "Posts" теперь кажется более отзывчивым, потому что сама кнопка вкладки сразу же обновляется:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
1 2 3 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
1 2 3 4 5 6 7 8 9 10 11 |
|
Предотвращение нежелательных индикаторов загрузки¶
В этом примере компонент PostsTab
получает некоторые данные, используя источник данных Suspense-enabled. Когда вы нажимаете на вкладку "Posts", компонент PostsTab
приостанавливается, вызывая появление ближайшего фалбэка загрузки:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Скрытие всего контейнера вкладки для отображения индикатора загрузки приводит к искажению пользовательского опыта. Если вы добавите useTransition
к TabButton
, вы можете вместо этого указать отображение состояния ожидания в кнопке вкладки.
Обратите внимание, что при нажатии на кнопку "Posts" весь контейнер вкладки больше не заменяется спиннером:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Подробнее об использовании переходов в Suspense.
Ожидание переходов
Переходы будут "ждать" только достаточно долго, чтобы избежать скрытия уже раскрытого содержимого (например, контейнера вкладки). Если вкладка Posts имеет вложенную границу <Suspense>
, переход не будет "ждать" ее.
Создание маршрутизатора с поддержкой Suspense
¶
Если вы создаете фреймворк React или маршрутизатор, мы рекомендуем помечать переходы по страницам как переходы.
1 2 3 4 5 6 7 8 9 10 11 |
|
Это рекомендуется по двум причинам:
- Переходы прерывисты, что позволяет пользователю щелкнуть мышью, не дожидаясь завершения повторного рендеринга.
- Переходы предотвращают нежелательные индикаторы загрузки, что позволяет пользователю избежать резких скачков при навигации.
Вот небольшой упрощенный пример маршрутизатора с использованием переходов для навигации.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Suspense-enabled ожидается, что маршрутизаторы по умолчанию будут оборачивать обновления навигации в переходы.
Отображение ошибки для пользователей с границей ошибки¶
Canary
Граница ошибки для useTransition
в настоящее время доступна только в канале React canary и экспериментальном канале.
Если функция, переданная в startTransition
, выкидывает ошибку, вы можете отобразить ее пользователю с помощью границы ошибки. Чтобы использовать границу ошибки, оберните компонент, в котором вызывается useTransition
, в границу ошибки. После того как функция, переданная в startTransition
, ошибется, будет отображена обратная связь для границы ошибки.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
|
Устранение неполадок¶
Обновление входа в переходе не работает¶
Вы не можете использовать переход для переменной состояния, которая управляет входом:
1 2 3 4 5 6 7 8 9 10 |
|
Это связано с тем, что переходы являются неблокирующими, но обновление ввода в ответ на событие изменения должно происходить синхронно. Если вы хотите запустить переход в ответ на ввод текста, у вас есть два варианта:
- Вы можете объявить две отдельные переменные состояния: одну для состояния ввода (которая всегда обновляется синхронно) и одну, которую вы будете обновлять в переходе. Это позволит вам управлять вводом, используя синхронное состояние, и передать переменную состояния перехода (которая будет "отставать" от ввода) остальной части вашей логики рендеринга.
- В качестве альтернативы вы можете иметь одну переменную состояния и добавить
useDeferredValue
, которая будет "отставать" от реального значения. Это вызовет неблокирующие повторные рендеринги, чтобы автоматически "догнать" новое значение.
React не рассматривает обновление моего состояния как переход¶
Когда вы оборачиваете обновление состояния в переход, убедитесь, что оно происходит во время вызова startTransition
:
1 2 3 4 |
|
Функция, которую вы передаете в startTransition
, должна быть синхронной.
Вы не можете пометить обновление как переход таким образом:
1 2 3 4 5 6 |
|
Вместо этого вы можете сделать следующее:
1 2 3 4 5 6 |
|
Точно так же вы не можете пометить обновление как переход:
1 2 3 4 5 |
|
Однако это работает вместо этого:
1 2 3 4 5 |
|
Я хочу вызвать useTransition
извне компонента¶
Вы не можете вызвать useTransition
вне компонента, потому что это Hook. В этом случае вместо него используйте отдельный метод startTransition
. Он работает так же, но не предоставляет индикатор isPending
.
Функция, которую я передаю в startTransition
, выполняется немедленно¶
Если вы запустите этот код, он выведет 1, 2, 3:
1 2 3 4 5 6 |
|
Ожидается, что будет выведено 1, 2, 3. Функция, которую вы передаете в startTransition
, не задерживается. В отличие от браузера setTimeout
, он не запускает обратный вызов позже. React выполняет вашу функцию немедленно, но все обновления состояния, запланированные пока она выполняется, помечаются как переходы. Вы можете представить, что это работает следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Источник — https://react.dev/reference/react/useTransition