React fiber что это

Русские Блоги

Понимание архитектуры React Fiber

Понимание архитектуры React Fiber

React Fiber is an ongoing reimplementation of React’s core algorithm. It is the culmination of over two years of research by the React team.

The goal of React Fiber is to increase its suitability for areas like animation, layout,and gestures. Its headline feature is incremental rendering: the ability to split rendering work into chunks and spread it out over multiple frames.

Other key features include the ability to pause, abort, or reuse work as new updates come in; the ability to assign priority to different types of updates; and new concurrency primitives.

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

Логика рендеринга компонентов до React16

Давайте посмотрим на жизненный цикл рендеринга компонентов React:

В предыдущей версии, если вы реализуете очень сложный глубоко вложенный составной компонент, произойдет следующее:

Существующие иерархические отношения выглядят следующим образом:

React fiber что это. c164dcbfda7cf8de7ec292d41804d9cd. React fiber что это фото. React fiber что это-c164dcbfda7cf8de7ec292d41804d9cd. картинка React fiber что это. картинка c164dcbfda7cf8de7ec292d41804d9cd

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

React fiber что это. 78cc0c580df1ae7e3db3230c86580735. React fiber что это фото. React fiber что это-78cc0c580df1ae7e3db3230c86580735. картинка React fiber что это. картинка 78cc0c580df1ae7e3db3230c86580735

На приведенном выше рисунке показана последовательность визуализации жизненного цикла вызовов фазы монтирования для A, B, C и D. Вы можете видеть, что каждый жизненный цикл вызывается из компонента верхнего уровня и идет вниз до тех пор, пока не будет вызван жизненный цикл подкомпонента нижнего уровня. Потом позвони снова.
То же самое касается фазы обновления компонентов.

После монтирования компонента, если данные (состояние) самого верхнего компонента изменены, стек вызовов при обновлении компонента:

React fiber что это. 5d9a20e9c9604636b1c0d9791fdf2de0. React fiber что это фото. React fiber что это-5d9a20e9c9604636b1c0d9791fdf2de0. картинка React fiber что это. картинка 5d9a20e9c9604636b1c0d9791fdf2de0

Появление React Fiber

React Fiber был создан для решения вышеуказанных проблем.

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

React fiber что это. bce3a7ea4939168f7cfd407ad8f41c38. React fiber что это фото. React fiber что это-bce3a7ea4939168f7cfd407ad8f41c38. картинка React fiber что это. картинка bce3a7ea4939168f7cfd407ad8f41c38

Для того, чтобы различать приоритеты, React имеет свой собственный набор логики. Для вещей с высокой производительностью в реальном времени, таких как анимация, то есть, если вы должны выполнить рендеринг один раз в 16 мс, чтобы гарантировать, что он не зависнет, React будет приостанавливать обновление каждые 16 мс (в пределах) и возвращаться для продолжения рендеринга анимации.

Архитектура React Fiber

Разделите планирование на небольшие задачи

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

React официально используетrequestIdleCallback, Чтобы быть совместимым со всеми платформами, facebook реализовал свои функции отдельно, как независимый пакет npm, используя response-schedule.

Его функция заключается в последовательном вызове функций во время периода простоя браузера, который может выполнять фоновые или низкоприоритетные задачи в основном цикле событий, не влияя на отложенный запуск и критические события, такие как анимация и взаимодействие с пользователем. Функции обычно выполняются в порядке первого вызова, если функция не достигает своего тайм-аута до того, как браузер ее вызовет.

Упрощенная блок-схема выглядит следующим образом:

React fiber что это. 139c502644b54400cd9e15025e362cd4. React fiber что это фото. React fiber что это-139c502644b54400cd9e15025e362cd4. картинка React fiber что это. картинка 139c502644b54400cd9e15025e362cd4

Волоконный узел и волоконное дерево

Два этапа: reconciliation с commit

процесс примирения

1 Если текущий узел обновлять не нужно, клонируйте дочерний узел напрямую и отметьте тип обновления, если вы хотите обновить
2 Обновите текущее состояние узла (свойства, состояние, контекст и т. д.)
3 вызвать shouldComponentUpdate ()
4 Вызовите метод экземпляра компонента render (), чтобы получить новый дочерний узел, и создайте Fiber Node для дочернего узла (процесс создания будет повторно использовать существующий Fiber Node в максимально возможной степени, и здесь также происходит добавление и удаление дочерних узлов. )
5 Если дочернее волокно не сгенерировано, введите следующую фазу completeUnitOfWork

Жизненный цикл состоит из двух фаз:

ReconciliationСтадия (Алгоритм React, используемый для сравнения двух деревьев, чтобы определить, какие части необходимо повторно отрендерить.

CommitСтадия (Используется для представления изменений данных в приложениях React. как правило setState результат. В конечном итоге приведет к повторному рендерингу.

Потому как reconciliation Этап может быть прерван, поэтому reconciliation Функции жизненного цикла, которые будут выполняться на этапе, могут вызываться несколько раз, что вызывает ошибки. Таким образом, для reconciliation Несколько функций, вызываемых в сцене, кроме shouldComponentUpdate Помимо этого, других следует избегать, и для решения этой проблемы в React16 был введен новый API.

getDerivedStateFromProps Заменил оригинал componentWillMount против componentWillReceiveProps Метод, который будет вызываться при инициализации и обновлении компонента.

Таким образом, весь процесс выглядит так: (цитируя изображение @ )

React fiber что это. c8dfcf7dd16fd8d467146e997650b83b. React fiber что это фото. React fiber что это-c8dfcf7dd16fd8d467146e997650b83b. картинка React fiber что это. картинка c8dfcf7dd16fd8d467146e997650b83b

Предложения по использованию функции жизненного цикла React16

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

Основное обновление 16-й версии также устраняет следующие болевые точки:

Источник

Fiber изнутри: подробный обзор нового алгоритма согласования в React

Oct 16, 2019 · 15 min read

React fiber что это. 1*gwgSW5BCe6W0mhtN20bErw. React fiber что это фото. React fiber что это-1*gwgSW5BCe6W0mhtN20bErw. картинка React fiber что это. картинка 1*gwgSW5BCe6W0mhtN20bErw

Помимо дерева React-элементов, фреймворк обязательно создаёт дерево внутренних узлов (компонентов, DOM-узлов и т.п.), используемое для хранения состояния. Начиная с 16 версии React обзавёлся новой реализацией этого дерева и новым алгоритмом для его обработки под названием Fiber. Чтобы узнать больше о преимуществах архитектуры Fiber, читайте “Как Fiber в React использует связанный список для обхода дерева компонентов” (оригинал)

Это первая статья в серии, объясняющей внутреннее устройство React. В этой статье я предлагаю вашему вниманию подробный обзор важнейших концепций и структур данных, связанных с алгоритмом Fiber. После знакомства с основами, мы исследуем сам алгоритм и основные функции, служащие для перемещения по fiber-дереву и для работы с его элементами. В последующих статьях серии будет продемонстрировано как React использует алгоритм для выполнения первого рендера и обработки изменения свойств и состояния. Затем мы детально рассмотрим планировщик, процесс согласования для детей и механизм построения списка эффектов.

Я собираюсь рассказывать довольно сложные вещи🧙‍. Прочтите этот материал, чтобы понять магию, приводящую React в движение. Также эта серия статей послужит для вас хорошим руководством в том случае, если вы планируете контрибьютить в репозиторий React. Я убеждён в невероятной пользе реверс-инжиниринга, так что впереди вас ждёт множество ссылок на исходный код.

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

Готовим реквизит

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

React fiber что это. 1*eet63qW5RNWwwEX41fuB6Q. React fiber что это фото. React fiber что это-1*eet63qW5RNWwwEX41fuB6Q. картинка React fiber что это. картинка 1*eet63qW5RNWwwEX41fuB6Q

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

Во время согласования производятся и другие действия, например вызов методов жизненного цикла или обновление рефов. Все такие действия в архитектуре Fiber называются “работа”. Тип совершаемой работы, как правило зависит от типа React-элемента. К примеру, для компонента-класса React должен создать его экземпляр, в то время как для функционального компонента этого делать не надо. Вам известно, что в React существует множество различных элементов: компоненты-классы, функциональные компоненты, хост-компоненты (DOM-ноды), порталы и т.п. Тип React-элемента определяется первым аргументом функции createElement. Эта функция, как правило, используется внутри метода render для создания элемента.

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

От React-элементов к Fiber-нодам

React-элементы

После обработки шаблона компилятором JSX, мы получим набор React-элементов. Именно их, а не HTML, возвращает метод render React-компонента. Если нам не обязательно использовать JSX, мы можем переписать метод render для ClickCounter следующим образом:

Вызов React.createElement внутри render создаст две вот такие структуры данных:

У React-элемента ClickCounter нет свойств(props) и атрибута key:

Fiber-ноды

Во время согласования данные каждого React-элемента, полученные из метода render сливаются в дерево fiber-нод. Для каждого React-элемента существует соответствующая ему fiber-нода. В отличие от React-элементов, Fiber-ноды не пересоздаются заново при каждом рендере. Это мутабельные структуры данных, содержащие состояние компонентов и DOM.

Вы можете рассматривать Fiber как структуру данных, описывающую некоторую работу или, другими словами, единицу работы. Архитектура Fiber также обеспечивает удобный способ отслеживания, планирования, приостановки и отмены работы.

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

Поскольку React создаёт Fiber-ноду для каждого React-элемента, а эти элементы выстраиваются в дерево, мы получаем и дерево Fiber-нод. В случае нашего простейшего приложения оно выглядит так:

React fiber что это. . React fiber что это фото. React fiber что это-. картинка React fiber что это. картинка

Текущее и workInProgress-дерево

После первого рендера у React есть fiber-дерево, отражающее состояние приложения, необходимое для отрисовки пользовательского интерфейса. Это дерево часто называют текущим(current). Когда React начинает обновления, он строит так называемое workInProgress-дерево, отражающее то состояние, что отрисуется на экране в будущем.

Одним из главных принципов React является консистентность. React всегда обновляет DOM в один присест — частичные результаты он не демонстрирует. workInProgress-дерево служит “черновиком”, невидимым для пользователя, и, таким образом, React может сначала обработать все компоненты, а потом отобразить изменения на экране.

В исходном коде вы увидите множество функций, принимающих в качестве аргументов ноды как из текущего(current), так и из workInProgress-дерева. Вот сигнатура одной из таких функций.

Каждая Fiber-нода содержит ссылку на своего визави из другого дерева в поле alternate. Ноды из текущего(current) дерева указывают на ноды из workInProgress-дерева и наоборот.

Побочные эффекты

Можно думать о React-компоненте, как о функции, использующей состояние(state) и свойства(props) для обсчёта пользовательского интерфейса. Все остальные действия, как-то: изменения DOM или вызов методов жизненного цикла следует рассматривать как побочный эффект или, попросту, эффект. Эффекты также упоминаются в документации:

Вам скорее всего доводилось ранее запрашивать данные, делать подписки или вручную менять DOM из React-компонента. Мы расцениваем эти операции как «побочные эффекты» (или сокращённо «эффекты»), так как они могут влиять на работу других компонентов и их нельзя выполнить во время рендера.

Список эффектов

React производит обновления очень быстро и для достижения такой производительности он применяет несколько любопытных техник. Одна из них — построение линейного списка Fiber-нод с эффектами для быстрого их перебора. Проход по линейному списку происходит значительно быстрее, чем проход по дереву и при этом не требуется тратить время на ноды без побочных эффектов.

React fiber что это. . React fiber что это фото. React fiber что это-. картинка React fiber что это. картинка

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

React fiber что это. 1*zvFYcc4lw8RR 0 3Yz7UKg. React fiber что это фото. React fiber что это-1*zvFYcc4lw8RR 0 3Yz7UKg. картинка React fiber что это. картинка 1*zvFYcc4lw8RR 0 3Yz7UKg

Видно, что React применяет эффекты начиная с детей и заканчивая родителями.

Корень fiber-дерева

React создаёт объект fiber-root для каждого из таких контейнеров. Вы можете получить доступ к нему при помощи ссылки на DOM-элемент.

fiberRoot — то место, где React хранит ссылку на fiber-дерево. Оно хранится в свойстве current fiberRoot.

Структура Fiber-ноды

Давайте посмотрим на структуру Fiber-нод, создаваемых для компонента ClickCounter :

и для DOM-элемента span :

stateNode
Содержит ссылку на экземпляр компонента-класса, DOM-узел или другой тип React-элемента, ассоциированного с Fiber-нодой. В общем и целом, можно сказать, что это свойство используется для хранения локального состояния, связанного с Fiber-нодой.

type
Указывает на функцию или класс, ассоциированный с Fiber-нодой. Для компонентов-классов, оно указывает на функцию-конструктор, а для DOM-элементов — содержит название HTML-тэга. Я постоянно использую это поле для того, чтобы определить к какому элементу относится Fiber-нода.

updateQueue
Очередь обновлений состояния, колбэков и обновлений DOM.

memoizedState
Состояние(state) Fiber-ноды, которое используется для создания вывода. Во время обработки обновлений, это поле отражает состояние, выведенное на экран в данный момент.

memoizedProps
Свойства(props) Fiber-ноды, использовавшиеся для создания вывода во время предыдущей отрисовки.

pendingProps
Свойства(props), которые изменились на основании новых данных в React-элементах и должны быть применены к дочерним компонентам или DOM-элементам.

key
Уникальный идентификатор, помогающий React сделать предположения о том, какие части приложения изменены, добавлены или удалены. “Списки и ключи” описаны в документации React здесь.

Алгоритм в общем

Вам ведь интересно узнать, с чем это связано?

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

Хорошо, теперь мы достаточно осведомлены для того, чтобы рассмотреть обобщённый алгоритм, использующийся для обхода дерева и обработки его составляющих. Давайте начнём.

Фаза render

Основные стадии рабочего цикла

Все Fiber-ноды обрабатываются в рамках рабочего цикла. Вот как выглядит асинхронная часть этого цикла:

Вот четыре основных функции, используемые для обхода дерева и запуска/завершения работы:

Чтобы увидеть, как они используются, давайте посмотрим на анимацию обхода fiber-дерева. Для демонстрационных целей я использовал упрощённую имплементацию этих функций. Каждая функция принимает в обработку Fiber-ноду и по мере продвижения React по дереву мы можем видеть, как изменяется текущая нода. На записи отчётливо видно, как алгоритм переходит с ветви на ветвь, завершая работу с детьми, прежде чем перейти к родителям.

React fiber что это. 1*TW1DAgg1pB SBJLymuoaQQ. React fiber что это фото. React fiber что это-1*TW1DAgg1pB SBJLymuoaQQ. картинка React fiber что это. картинка 1*TW1DAgg1pB SBJLymuoaQQ

Обратите внимание, что вертикальные черты обозначают сиблингов, а согнутые под прямым углом — детей, например у b1 детей нет, а у b2 — есть один ( c1 ).

Вот здесь ссылка на видео, где вы можете остановить проигрывание и исследовать состояние текущей ноды. Концептуально, вы может думать, что “начало” — это “вход” в компонент, а “завершение” — выход из него. Также вы может поэкспериментировать с примером здесь.

Давайте начнём с первых двух функций performUnitWork и beginWork :

Фаза commit

Эта фаза начинается с функции completeRoot. Здесь React обновляет DOM и вызывает премутационные и постмутационные методы жизненного цикла.

Вот функция, запускающая шаги, описанные выше:

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

Премутационные методы жизненного цикла

Вот, к примеру, код, проходящий по дереву эффектов и проверяющий, помечена ли нода эффектом Snapshot :

Для компонента-класса, этот эффект означает вызов метода жизненного цикла getShapshotBeforeUpdate

Обновления DOM

commitAllHostEffects — функция, внутри которой React выполняет обновления DOM. Эта функция определяет тип операции, которую необходимо произвести и выполняет её.

Постмутационные методы жизненного цикла

commitAllLifecycles — функция, в которой React вызывает все остальные методы жизненного цикла.

Источник

Concurrent Mode в React: адаптируем веб-приложения под устройства и скорость интернета

В этой статье я расскажу о конкурентном режиме в React. Разберёмся, что это: какие есть особенности, какие новые инструменты появились и как с их помощью оптимизировать работу веб-приложений, чтобы у пользователей всё летало. Конкурентный режим — новая фишка в React. Его задача — адаптировать приложение к разным устройствам и скорости сети. Пока что Concurrent Mode — эксперимент, который может быть изменён разработчиками библиотеки, а значит, новых инструментов нет в стейбле. Я вас предупредил, а теперь — поехали.

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

React fiber что это. image loader. React fiber что это фото. React fiber что это-image loader. картинка React fiber что это. картинка image loader

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

Concurrent Mode — это Fiber-архитектура

Конкурентный режим — это не новая штука, которую разработчики внезапно решили добавить, и всё тут же заработало. К его выходу готовились заранее. В 16-й версии движок React переключили на Fiber-архитектуру, которая по принципу работы напоминает планировщик задач в операционной системе. Планировщик распределяет вычислительные ресурсы между процессами. Он способен переключаться в любой момент времени, поэтому у пользователя возникает иллюзия, что процессы работают параллельно.

Fiber-архитектура делает то же самое, но с компонентами. Несмотря на то, что она уже есть в React, Fiber-архитектура будто находится в анабиозе и не использует свои возможности по максимуму. Конкурентный режим включит её на полную мощность.

При обновлении компонента в обычном режиме приходится целиком рисовать новый кадр на экране. Пока обновление не завершится, пользователь ничего не увидит. В этом случае React работает синхронно. Fiber использует другую концепцию. Каждые 16 мс происходит прерывание и проверка: изменилось ли виртуальное дерево, появились ли новые данные? Если да, пользователь увидит их сразу.

Почему 16 мс? Разработчики React стремятся, чтобы перерисовка экрана происходила на скорости, близкой к 60 кадрам в секунду. Чтобы уложить 60 обновлений в 1000 мс, нужно осуществлять их примерно каждые 16 мс. Отсюда и цифра. Конкурентный режим включается «из коробки» и добавляет новые инструменты, которые делают жизнь фронтендера лучше. Расскажу о каждом подробно.

Suspense

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

Suspense в конкурентном режиме читает данные, которые ещё не готовы. Как? Запрашиваем данные, а пока они не пришли целиком, уже начинаем читать их по небольшим кусочкам. Самая крутая фишка для разработчиков — это управление порядком отображения загруженных данных. Suspense позволяет отображать компоненты страницы как одновременно, так и независимо друг от друга. Он делает код понятным: достаточно взглянуть на структуру Suspense, чтобы узнать, в каком порядке запрашиваются данные.

Типичное решение для загрузки страниц в «старом» React — Fetch-On-Render. В этом случае мы запрашиваем данные после render внутри useEffect или componentDidMount. Это стандартная логика в случае, когда нет Redux или другого слоя, работающего с данными. Например, мы хотим нарисовать 2 компонента, каждому из которых нужны данные:

Рассмотрим другой способ, Fetch-Then-Render: сначала запрашиваем все данные, потом отрисовываем страничку.

Может показаться, что такой подход близок к Fetch-On-Render, когда мы запрашивали данные после отрисовки первого компонента. Но на самом деле с использованием Suspense данные придут гораздо быстрее. Всё благодаря тому, что оба запроса отправляются параллельно.

В Suspense можно указать fallback, компонент, который хотим отобразить, и внутрь компонента передать ресурс, реализуемый библиотекой получения данных. Мы используем его as is. Внутри компонентов запрашиваем данные с ресурса и вызываем метод чтения. Это promise, который делает за нас библиотека. Suspense поймёт, загрузились ли данные, и если да — покажет их.

Обратите внимание, что компоненты пробуют читать данные, которые ещё находятся в процессе получения:

В текущих демках Дэна Абрамова в качестве заглушки для ресурса используется такая штука.

Если ресурс ещё загружается, мы выбрасываем объект Promise в качестве исключения. Suspense ловит это исключение, понимает, что это Promise, и продолжает грузиться. Если же вместо Promise прилетит исключение с любым другим объектом, станет понятно, что запрос завершился ошибкой. Когда же вернётся готовый результат, Suspense его отобразит. Нам важно получить ресурс и вызвать у него метод. Как это реализовано внутри — решение разработчиков библиотеки, главное, чтобы их реализацию понимал Suspense.

Когда запрашивать данные? Запрашивать наверху дерева — не лучшая идея, потому что они могут никогда не потребоваться. Более подходящий вариант — делать это сразу при переходе внутри обработчиков событий. Например, получить начальное состояние через хук, а дальше делать запрос за ресурсами, как только пользователь нажмёт на кнопку.

Вот как это будет выглядеть в коде:

Suspense — невероятно гибкая штука. С его помощью можно отображать компоненты друг за другом.

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

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

Кроме того, компоненты Error Boundary поймают ошибки внутри Suspense. Если что-то пошло не так, мы сможем показать, что пользователь загрузился, а посты нет, и выдать ошибку.

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

SuspenseList

SuspenseList в конкурентном режиме помогает управлять порядком загрузки Suspense. Если бы нам потребовалось загрузить несколько Suspense строго друг за другом без него, их бы пришлось вложить друг в друга:

SuspenseList позволяет сделать это гораздо проще:

Гибкость SuspenseList поражает. Можно как угодно вкладывать SuspenseList друг в друга и настраивать порядок загрузки внутри так, как будет удобно для отображения виджетов и любых других компонентов.

useTransition

Специальный хук, который откладывает обновление компонента до полной готовности и убирает промежуточное состояние загрузки. Для чего это нужно? React при изменении состояния стремится сделать переход как можно быстрее. Но иногда важно не торопиться. Если на действие пользователя подгружается часть данных, то обычно в момент загрузки мы показываем лоадер или скелетон. Если данные придут очень быстро, то лоадер не успеет совершить даже пол-оборота. Он моргнёт, затем исчезнет, и мы нарисуем обновлённый компонент. В таких случаях разумнее вообще не показывать лоадер.

Здесь на помощь придёт useTransition. Как он работает в коде? Вызываем хук useTransition и указываем тайм-аут в миллисекундах. Если данные не придут за указанное время, то мы всё равно покажем лоадер. Но если получим их быстрее, произойдёт моментальный переход.

Иногда при переходе на страницу мы не хотим показывать лоадер, но всё равно нужно что-то изменить в интерфейсе. Например, на время перехода заблокировать кнопку. Тогда придётся кстати свойство isPending — оно сообщит, что мы находимся в стадии перехода. Для пользователя обновление будет моментальным, но здесь важно отметить, что магия useTransition действует только на компоненты, обёрнутые в Suspense. Сам по себе useTransition не заработает.

Переходы часто встречаются в интерфейсах. Логику, отвечающую за переход, было бы здорово зашить в кнопку и интегрировать в библиотеку. Если есть компонент, ответственный переходы между страницами, можно обернуть в handleClick тот onClick, который передаётся через пропсы в кнопку, и показать состояние isDisabled.

useDeferredValue

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

Сейчас React так не умеет: в текущей версии на экране пользователя могут отображаться только данные из актуального состояния. Но useDeferredValue в конкурентном режиме умеет возвращать отложенную версию значения, показывать устаревшие данные вместо мигающего лоадера или fallback во время загрузки. Этот хук принимает значение, для которого мы хотим получить отложенную версию, и задержку в миллисекундах.

Интерфейс становится супер текучим. Производить обновления можно с минимальным количеством данных, а всё остальное грузится постепенно. У пользователя создаётся впечатление, что приложение работает быстро и плавно. В действии useDeferredValue выглядит так:

Можно сравнить значение из пропсов с тем, что получено через useDeferredValue. Если они отличаются, значит страница ещё находится в состоянии загрузки.

Интересно, что useDeferredValue позволит повторить фокус с отложенной загрузкой не только для данных, которые передаются по сети, но и для того, чтобы убрать фриз интерфейса из-за больших вычислений.

Почему это здорово? Разные устройства работают по-разному. Если запустить приложение, использующее useDeferredValue, на новом iPhone, переход со страницы на страницу будет моментальным, даже если страницы тяжёлые. Но при использовании debounced задержка появится даже на мощном устройстве. UseDeferredValue и конкурентный режим адаптируются к железу: если оно работает медленно, инпут всё равно будет летать, а сама страничка — обновляться так, как позволяет устройство.

Как переключить проект в Concurrent Mode?

Конкурентный режим — это именно режим, поэтому его потребуется включить. Как тумблер, который заставляет Fiber работать на полную мощность. С чего же начать?

Убираем легаси. Избавляемся от всех устаревших методов в коде и убеждаемся, что их нет в библиотеках. Если приложение без проблем работает в React.StrictMode, то всё в порядке — переезд будет простым. Потенциальная сложность — проблемы внутри библиотек. В этом случае нужно либо перейти на новую версию, либо сменить библиотеку. Или же отказаться от конкурентного режима. После избавления от легаси останется только переключить root.

С приходом Concurrent Mode будет доступно три режима подключения root:

Выводы

Блокирующие операции внутри React превращаются в асинхронные за счёт переключения на Fiber. Появляются новые инструменты, с которыми легко адаптировать приложение и к возможностям устройства, и к скорости сети:

Оцените свои проекты — что можно улучшить, используя новые инструменты? А когда конкурентный режим выйдет, смело переезжайте. Всё будет супер!

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *