⚛️ Is React Suspense Ready Yet?
Тред о том, чему можно поучиться у инженеров «FB», что закладывали Suspense-логику в реконсилер.
Ну... помимо того, что код можно ещё и релизить.
Disclaimer:
Подчеркну, что тред — исследование внутреннего устройства и попытки понять решения инженеров.
Призыва к использованию здесь нет.
Вообще, первое впечатление о Suspense, достаточно обескураживающее.
- Во-первых, ты думаешь, что это компонент.
- Во-вторых, ты понимаешь, что этот «сахар» не особо-то впечатляет:

Но если всё же начать разбираться и понять, что «Suspense» — термин, а затем разложить его на составляющие, то их будет всего две:
React.lazy() - отвечает за разбиение кода
Кэш - отвечает за кэширование данных от API
C Reat.lazy() все знакомы — компонент для код-сплиттинга.

И для того, чтобы заменять fallback-компонент, на тот, что загружается, тут используется «алгебраический эффект».
Объяснение в 5 строк внизу на картинке, а солидная статья по этой ссылке: overreacted.io/algebraic-effe…

Со вторым компонентом Suspens'а (кэшем) всё неопределённо.
С ним непонятно что делать. Уже второй год.
В документации так и написано: reactjs.org/docs/concurren…

Принцип работы React-компонента с кэшем аналогичен — бросить из компонента асинхронную функцию к API, так как для неё уже инкапсулирован обработчик в <Suspense />.

В этот момент происходит первая фаза понимания паттерна — отрицание.
— «Всмысле, кидать промис из компонента?»

Затем, «гнев».
— «Так мне ещё и кэш самому надо инвалидировать? А давно это надо делать на фронте?»

Потом, торгуешься, но всё же делаешь первую реализацию своего нерабочего кэша (на картинке).
— А что, пускай отдыхает 😎
Потом, погружаешься в тему и узнаешь про LRU-алгоритм, так как объект — так-себе кэш.
ru.bmstu.wiki/LRU_(Least_Rec…

В конце приходит и понимание того, что в Suspense, так-то, содержится конструкция
catch
, которая ожидает выбрасывания промиса от API...
...но ты использовал этот потенциал только для React.lazy() 😶О да, и вот, без лишних предисловий, 20 твитов спустя, мы у чего-то интересного. 👏
Понятие Suspense не ограничивается только отложенной загрузкой компонентов и данных.
Рассмотрим нестабильный компонент <SuspenseList />, что способен делать композицию из <Suspense />.
В документации всего 1 абзац. Зато в репозитории есть тесты. Их и почитаем.
Про параметр
revealOrder
можно узнать самостоятельно. Из одноабзацевой документации.
Сейчас же, мы приглядимся что Энрю Кларк покрыл тестами для пропа tail
.Опция
tail
имеет 2 состояния.
Нам интересен tail="collapsed"
, что использует алгоритм отображения компонентов строго очереди, а не по готовности.
Десонмтрация работы алгоритма: suspensive-react.artbelov.now.sh/74
листайте вправо.
Продублирую работу алгоритма...
Дано: 4 компонента, обёрнутые в SuspenseList c
tail="collapsed"
.
Hint: Начните следить за судьбой компонента <D /> 👀
1 коммит: 3 фоллбэк-компонента из 4. Где <D />? 😒

2 и 3 коммит — поочерёдная вставка загрузившихся компонентов <A /> и <B />.
4 коммит — одновременная вставка загрузившихся компонентов <C /> и <D />. (О, повезло-повезло...)
а вот фоллбэк-компонента <D /> так никто и не видел. 👀

Реконсилер в реакте штука сложная и она знает цену коммита в (Virtual)DOM. Это дорого.
А конкретно в данном случае, было заранее просчитано, что рендерить фоллбэк-компонент - нецелесообразно.
Фактически — реконсилер сэкономил на рендере фоллбэк-компонента, а к следующей транзакции уже был готов и сам загружаемый компонент.
Итого, Suspense своей реализацией показывает:
DX — это важно.
Кэш — это то, с чем уже пора учиться работать.
Для больших транзакций, рациональнее считать время планируемых работ, нежели выполнять инструкции.
Ибо если всё важно... то может ничего не важно?