Этот новый синтаксис хочет заменить JSX

BBetter Stack
컴퓨터/소프트웨어AI/미래기술

Transcript

00:00:00Сначала у нас был JSX, потом появился TSX, но мы застряли на них уже на годы.
00:00:04Неужели их нельзя улучшить? Ну, возможно, с помощью TSRX.
00:00:08Это вроде бы то же самое, но в то же время другое.
00:00:10У нас здесь не функция, а компонент, для текста используются обычные строки,
00:00:14внутри обычный оператор if, а еще нет инструкции return.
00:00:17Так что же это такое, зачем оно нужно и стоит ли его использовать? Давайте выясним.
00:00:21[Музыка]
00:00:26Возможно, некоторые из вас уже видели подобный код раньше,
00:00:29и это потому, что его создал создатель Ripple.
00:00:31Это новый фронтенд-фреймворк, о котором Рич рассказывал на этом канале полгода назад,
00:00:35так что подписывайтесь, чтобы быть в курсе таких вещей.
00:00:38Разработчики выделили синтаксис, используемый в Ripple,
00:00:41и заставили его работать с React, Preact, Solid, Vue и, конечно же, с самим Ripple,
00:00:45и многие люди были этим очень воодушевлены.
00:00:47TSRX позиционирует себя как способ написания UI-компонентов, которые остаются читаемыми и локализованными,
00:00:52где структура, стили и логика управления живут вместе,
00:00:55а результат остается полностью обратно совместимым с TypeScript.
00:00:58Но если вы не пользовались Ripple раньше, вы, скорее всего, все еще не совсем понимаете, что это значит,
00:01:01так что давайте разберем его возможности.
00:01:03Для начала, вы используете его с файлами .tsrx, что означает необходимость этапа компиляции,
00:01:07но это супер легко настроить с помощью плагина для Vite,
00:01:10а также есть другие варианты для других фреймворков и сред выполнения.
00:01:13Что касается самих компонентов: вместо написания function мы пишем component,
00:01:17и это в основном просто ключевое слово для самого компилятора,
00:01:20но оно также дает понять, что здесь будет содержаться логика рендеринга.
00:01:24Я бы назвал это небольшим улучшением качества жизни разработчика.
00:01:27Однако стоит заметить, что у нас здесь нет инструкции return,
00:01:30и это потому, что TSRX использует JSX на основе инструкций (statement-based),
00:01:33так что вам не нужно возвращать дерево компонентов,
00:01:35вы просто пишете разметку там, где хотите ее отрендерить.
00:01:37Это значит, что мы можем просто вставить еще один тег абзаца выше этой карточки в самом верху компонента,
00:01:42и он отрендерится именно там, где написан.
00:01:44Вы все еще можете использовать return в компоненте, но он должен быть пустым,
00:01:47и он используется только для раннего выхода, чтобы пропустить UI и логику после него.
00:01:51Мне помогает думать о компонентах TSRX как о линейных структурах,
00:01:54где порядок написания в коде соответствует порядку рендеринга,
00:01:57просто читая сверху вниз,
00:01:59но я также вижу, что из-за этого может быть сложнее быстро понять, что именно рендерит компонент,
00:02:03в то время как в том же React мы бы просто сразу переместились к инструкции return.
00:02:06Еще одно преимущество JSX на основе инструкций в том, что мы можем использовать гораздо больше обычного JavaScript.
00:02:10Например, условный рендеринг становится очень простым.
00:02:13Это просто оператор if, с else-if и else, если они вам нужны.
00:02:17В условиях нам просто нужно поместить наш JSX как инструкцию.
00:02:20Такая же логика в React часто превращается во вложенные тернарные операторы,
00:02:23потому что в JSX каждая ветка должна быть выражением,
00:02:26так что версия на TSRX иногда читается проще,
00:02:29особенно когда у нас более сложное условие,
00:02:31но в то же время я вижу, что это может добавить избыточности кода,
00:02:35особенно когда нужно простое условие.
00:02:37То же самое касается и операторов switch.
00:02:39Вы можете использовать обычный JavaScript switch с вашими кейсами
00:02:41и JSX, который вы хотите отрендерить для каждого из них.
00:02:44Это немного проще, чем то, как вы бы обрабатывали это в React,
00:02:47где для использования такого паттерна вам понадобилась бы функция,
00:02:49так что TSRX здесь выглядит немного чище,
00:02:51но область, которая лично мне в TSRX нравится меньше — это рендеринг списков.
00:02:55Здесь мы отказываемся от .map и вместо этого используем цикл for-of,
00:02:58и TSRX фактически расширил этот цикл, чтобы мы могли получать как индекс,
00:03:01так и стабильный идентификатор с помощью key.
00:03:03Затем, когда вы хотите пропустить элемент, вы можете просто использовать continue,
00:03:06так что это снова ближе к чистому JavaScript,
00:03:08но, как я уже сказал, лично я очень привык к использованию .map, filter и так далее,
00:03:12поэтому я, скорее всего, буду придерживаться их,
00:03:14и также стоит отметить, что вы не можете использовать другие типы циклов,
00:03:17такие как for, for-in, while и do-while.
00:03:19Это работает только для цикла for-of.
00:03:21Продолжая тему использования обычного JavaScript,
00:03:23предохранители ошибок (error boundaries) в TSRX реализуются с помощью простого блока try-catch.
00:03:27Ничего сложного и все предельно понятно.
00:03:30Мы также можем использовать тот же блок try-catch, если нам нужны асинхронные границы,
00:03:33нам просто нужно добавить блок pending
00:03:35и затем написать там ваш компонент загрузки.
00:03:38Компилятор сам заботится о том, чтобы взять этот код
00:03:40и преобразовать его под тот фреймворк, который вы используете,
00:03:42так что в React, Preact и Solid под капотом используется lazy,
00:03:45а в Ripple — эквивалент из Ripple.
00:03:47Если говорить конкретно о React,
00:03:48функции, которые мы рассмотрели на данный момент,
00:03:50кажется, позволяют нам нарушить одно из ключевых правил React —
00:03:53правило хуков.
00:03:54Теперь мы можем размещать их после условий, ранних возвратов
00:03:57и даже внутри циклов.
00:03:58Все они будут работать как обычно.
00:04:00Это позволяет нам лучше группировать код там, где он действительно нужен,
00:04:03при этом итоговый результат даже не нарушает правил.
00:04:06Компилятор просто незаметно поднимает (hoist) каждый хук в начало сгенерированной функции,
00:04:09так что React по-прежнему видит их в стабильном порядке,
00:04:11но вы получаете возможность писать их там, где им самое место.
00:04:14Для меня, как для человека, использующего React годами,
00:04:16это одна из тех вещей, к которым мне трудно привыкнуть,
00:04:18а еще это функция, где мы заставляем компилятор
00:04:20делать слишком много магии за кулисами,
00:04:22особенно завязанной на конкретный фреймворк,
00:04:24и мне кажется, что при отладке такого кода
00:04:26я мог бы запутаться в том, какая часть кода где находится.
00:04:28Но далее у нас идет лексическая область видимости,
00:04:30так что каждый вложенный элемент создает свою собственную область,
00:04:32благодаря чему мы можем объявить const label в трех разных блоках div,
00:04:36и они не будут конфликтовать.
00:04:37Здесь даже есть один в самом верху функции, который нигде не читается,
00:04:40и он тоже не вызывает конфликтов.
00:04:41То же самое относится к любому оператору if, for, switch или try.
00:04:44У каждого из них свои области видимости,
00:04:46так что переменные, которые мы объявляем, функции, которые запускаем,
00:04:48и значения, которые мы получаем, не утекают в другие области.
00:04:51Это еще одна из тех функций, которая направлена на локализацию нашего кода,
00:04:54и опять же, она заставляет наши компоненты читаться линейно, сверху вниз.
00:04:57Переходя теперь от JavaScript к стилизации, давайте поговорим о стилях.
00:05:00В TSRX у нас есть изолированные (scoped) стили,
00:05:02так что вы можете просто поместить блок style в ваш компонент,
00:05:04и CSS, который мы там пишем, применяется только к этому компоненту,
00:05:08при этом к имени класса при компиляции добавляется уникальный хеш.
00:05:11Так, этот компонент карточки имеет класс card,
00:05:13и обратите внимание: здесь дочерний элемент тоже пытается использовать этот класс card,
00:05:16но он не получает никаких стилей карточки,
00:05:17потому что у него нет собственного блока style.
00:05:19Он не получает стили от родителя,
00:05:21потому что у него нет этого уникального хеша.
00:05:22Если же вы хотите делиться стилями между компонентами,
00:05:24в TSRX есть ключевое слово style,
00:05:26с помощью которого родитель передает имя стиля
00:05:29компоненту, принимающему className в качестве пропса,
00:05:31и это гарантирует, что сгенерированный уникальный хеш передастся вместе с ним.
00:05:35Так что теперь дочерний элемент имеет тот же стиль, что и родитель.
00:05:37Технически вы также можете использовать глобальный селектор вокруг ваших стилей,
00:05:40чтобы выйти за рамки изоляции и применить эти стили глобально,
00:05:42но я думаю, что это приведет к путанице,
00:05:44и вы потеряете контроль над тем, откуда берутся ваши стили.
00:05:46Лично я сторонник Tailwind до мозга костей,
00:05:48так что я вряд ли буду часто использовать эту функцию
00:05:50и останусь на Tailwind,
00:05:51но тем не менее это довольно круто.
00:05:53Далее идет функция для тех из вас, кто был внимателен.
00:05:56В блоках кода, которые я показывал,
00:05:57была небольшая разница в том, как обрабатывается текст в этих инструкциях.
00:06:01Простой текст внутри элемента должен быть в двойных кавычках.
00:06:04Мы не можем просто написать его, как в JSX.
00:06:07Вы все еще можете использовать динамические значения,
00:06:08например, в такой строке,
00:06:10которая находится между двумя строками в двойных кавычках,
00:06:12и TSRX просто объединит это в одну строку при компиляции.
00:06:16Еще один вариант — просто придерживаться использования шаблонных литералов.
00:06:19Результат будет тот же.
00:06:20Для меня это стало одним из раздражающих моментов при использовании TSRX,
00:06:23потому что у меня выработалась сильная мышечная память не использовать кавычки для текста.
00:06:26Однако еще одна функция, связанная с текстом,
00:06:27заключается в том, что TSRX может обрабатывать строки, содержащие реальную HTML-разметку,
00:06:31и у вас есть два способа ее отрендерить.
00:06:33Первый — просто использовать ключевое слово text,
00:06:35которое отрендерит экранированный текст,
00:06:38так что вы увидите буквальную HTML-строку,
00:06:40и это также защищает от межсайтового скриптинга (XSS).
00:06:42Это полезно, когда вы хотите гарантировать, что на выходе будет строка,
00:06:45а источник этой строки немного неоднозначен,
00:06:48так что вы не обязательно знаете ее тип во время написания кода.
00:06:51Второй вариант — если вы хотите отрендерить строку как HTML,
00:06:54мы можем просто использовать ключевое слово HTML,
00:06:56и это распарсит ее как настоящий HTML,
00:06:58но эта функция работает только в Ripple, а Vue поддерживает лишь ее узкое подмножество.
00:07:02Другая функция, не связанная с React,
00:07:03но которая может быть интересна тем из вас, кто использует Ripple,
00:07:06Vue или Solid — это ленивая деструктуризация (lazy destructuring).
00:07:08Если вы деструктурируете пропсы обычным образом в этих фреймворках,
00:07:10вы фиксируете каждое значение в момент вызова,
00:07:12и это нарушает реактивность при каждом обращении.
00:07:14Поэтому в TSRX вы можете просто добавить амперсанд перед пропсами,
00:07:18и хотя это выглядит как деструктуризация,
00:07:20каждая привязка на самом деле компилируется обратно в поиск свойства там, где она используется.
00:07:23Таким образом, среда выполнения видит каждое обращение индивидуально,
00:07:25так что обновления сигналов по-прежнему вызывают повторные рендеринги,
00:07:28а это значит, что вы сохраняете удобство деструктуризации,
00:07:30а фреймворк сохраняет свою реактивность.
00:07:32Последняя функция, которую я покажу, — приятное и простое улучшение удобства использования.
00:07:35Бывал ли у вас проп, значение которого имеет то же имя, что и сам проп —
00:07:40чаще всего в чем-то вроде функции on-change?
00:07:42Что ж, в TSRX вы можете просто написать это в сокращенном виде,
00:07:45подобно тому, как мы делаем с объектами в JavaScript.
00:07:47Это чисто и просто.
00:07:49В целом, TSRX выглядит как попытка вернуть обычный поток JavaScript обратно в JSX
00:07:53и при этом добавить несколько приятных улучшений для удобства разработки,
00:07:55и мне действительно нравятся многие его элементы.
00:07:57Искренне считаю, что его главный недостаток в том, что он слишком нишевый и появился слишком поздно,
00:08:01когда ИИ пишет большую часть нашего кода,
00:08:03а код, который ИИ пишет хорошо, — это в основном JSX и React.
00:08:07При этом я все же скормил Клоду несколько демо-примеров с TSRX,
00:08:10и он справился с написанием кода хорошо, просто основываясь на файле llms.txt этого сайта,
00:08:14но я все равно, пожалуй, останусь на обычном React.
00:08:17Другой минус в том, что, особенно для React,
00:08:19это добавляет еще больше магии компилятора сверху,
00:08:21а также ломает паттерны разработки, которые я изучал годами,
00:08:24так что лично мне это не подходит, но это не значит, что технология плохая.
00:08:27Думаю, людям, переходящим со Svelte, это может очень понравиться,
00:08:30а если вы уже использовали Ripple, вы, скорее всего, уже в восторге от этого.
00:08:33Так что дайте мне знать об этом в комментариях внизу,
00:08:35заодно подписывайтесь и, как всегда, увидимся в следующем видео.
00:08:40[Музыка]

Key Takeaway

Синтаксис TSRX переносит привычные конструкции JavaScript вроде циклов for-of, блоков try-catch и операторов if-else напрямую в разметку компонентов React, Solid, Vue и Ripple, избавляя разработчиков от тернарных операторов и метода .map за счет возможностей компилятора.

Highlights

  • Синтаксис TSRX позволяет писать компоненты без использования инструкции return за счет использования JSX на основе инструкций (statement-based JSX).

  • Компилятор TSRX автоматически поднимает (hoist) хуки React в начало функции, позволяя безопасно вызывать их внутри циклов и после условных операторов.

  • Изоляция стилей в TSRX достигается путем добавления уникального хеша к именам классов при компиляции, предотвращая утечку стилей за пределы компонента.

  • Для рендеринга списков в TSRX используется расширенный цикл for-of, который позволяет получать индекс элемента и стабильный ключ через специальное свойство key.

  • Ленивая деструктуризация пропсов с помощью префикса амперсанда (&) сохраняет реактивность сигналов в Ripple, Vue и Solid за счет компиляции в точечный доступ к свойствам.

Timeline

Концепция линейного рендеринга без инструкции return

  • Синтаксис TSRX заменяет объявление функций на ключевое слово component для упрощения структуры кода.
  • Отсутствие инструкции return в компонентах TSRX реализуется за счет JSX на основе инструкций.
  • Рендеринг компонентов происходит линейно сверху вниз в порядке объявления элементов в коде.

Новый синтаксис разработан создателем фреймворка Ripple и адаптирован для работы с React, Preact, Solid, Vue. Файлы с расширением .tsrx компилируются с помощью плагина для Vite. Инструкция return в компонентах используется исключительно в качестве пустого оператора для раннего выхода из рендеринга.

Использование стандартных управляющих конструкций JavaScript вместо паттернов JSX

  • Условный рендеринг в TSRX записывается через стандартные операторы if, else-if и else вместо тернарных операторов.
  • Рендеринг списков выполняется через расширенный цикл for-of с поддержкой ключевых слов key и continue.
  • Обработка ошибок и асинхронная загрузка реализуются через стандартные блоки try-catch с секцией pending.

Применение конструкции switch-case избавляет от необходимости оборачивать сложную условную логику в отдельные функции. В циклах for-of заблокировано использование альтернативных циклов вроде while или обычного for. Для интеграции асинхронных границ компилятор преобразует блоки try-catch с секцией pending в ленивую загрузку компонентов через lazy под капотом React, Preact и Solid.

Обход правил хуков React и лексические области видимости

  • Компилятор TSRX автоматически переносит вызовы хуков в начало результирующей функции для соблюдения правил React.
  • Разработчики получают возможность группировать хуки внутри условных блоков и циклов непосредственно рядом с местом их использования.
  • Каждая инструкция if, for, switch и try создает собственную изолированную область видимости переменных.

Автоматическое поднятие хуков (hoisting) позволяет визуально локализовать логику без нарушения порядка вызовов при выполнении кода в React. Лексическая область видимости гарантирует, что переменные с одинаковыми именами, объявленные в разных блоках разметки, не конфликтуют между собой. Это упрощает чтение кода сверху вниз, но усложняет процесс отладки из-за скрытых преобразований компилятора.

Изолированные стили и передача классов

  • Локальные стили внутри тега style изолируются в пределах компонента за счет генерации уникального хеша.
  • Передача стилей дочерним компонентам осуществляется с помощью специального ключевого слова style.
  • Глобальные селекторы позволяют выйти за рамки изоляции стилей в случае необходимости.

Дочерние элементы по умолчанию защищены от наследования стилей родителя, даже если они используют аналогичные имена классов. При передаче стиля через соответствующее ключевое слово родительский компонент транслирует сгенерированный уникальный хеш в проп className дочернего элемента. При интеграции с утилитарными CSS-фреймворками вроде Tailwind CSS данные возможности изоляции стилей остаются невостребованными.

Особенности работы с текстом и реактивная деструктуризация пропсов

  • Любой статический текст в разметке TSRX должен быть явно обернут в двойные кавычки.
  • Вывод безопасного или сырого HTML-кода реализуется через ключевые слова text и HTML соответственно.
  • Префикс амперсанда перед деструктурируемыми пропсами сохраняет реактивность сигналов в Vue, Solid и Ripple.

Синтаксис TSRX не позволяет писать текст без кавычек напрямую внутри тегов, как это делается в стандартном JSX. Ключевое слово HTML для рендеринга неэкранированных строк поддерживается в основном в Ripple и имеет ограниченную поддержку во Vue. Ленивая деструктуризация преобразует обращение к переменным в точечный доступ к свойствам объекта во время компиляции, предотвращая потерю связи с реактивными сигналами.

Community Posts

No posts yet. Be the first to write about this video!

Write about this video