00:00:00Вы фанат Python до мозга костей? Я имею в виду, из тех людей, кто хочет писать только на Python
00:00:05и ни на чем больше? Что ж, если это про вас, то у меня есть кое-что интересное. Это фреймворк под названием
00:00:11Reflex, и он призван избавить вас от сложностей и проблем при превращении фулстек-кода на Python
00:00:17в готовые к работе веб-приложения. В этом видео мы разберем, что такое
00:00:22Reflex, как он работает, и выясним, оправдан ли весь этот хайп вокруг него.
00:00:30Основная проблема, которую решает Reflex, — это необходимость для Python-разработчиков учить
00:00:36совершенно другой стек, включая JavaScript, React, роутинг и бандлеры, просто чтобы
00:00:43создать функциональный веб-интерфейс для своего кода. Reflex позволяет собирать фулстек-приложения
00:00:50на 100% чистом Python, так что вы можете использовать один язык для всего стека,
00:00:56не переключая контекст. Создатели заявляют, что с момента запуска разработчики создали более 1 миллиона приложений
00:01:03на этом фреймворке, а 30% компаний из списка Fortune 500 используют его для
00:01:10своих внутренних инструментов. Недавно они сделали упор на ИИ и запустили
00:01:15инструмент Reflex Build, который позволяет буквально «навайбить» приложение из одного промпта.
00:01:21К тому же, они поддерживают интеграции с другими SDK и сервисами, позволяя легко подключать
00:01:26приложение к Databricks, Okta, Stripe, AWS и прочим. Звучит впечатляюще,
00:01:34но мне хочется проверить всё на практике и посмотреть, как этот код работает на самом деле.
00:01:40Начнем с создания новой директории ReflexTest и перейдем в нее. Судя по
00:01:44документации, нам нужно запустить три команды для старта проекта Reflex. Сначала
00:01:48выполним pip install reflex, а затем reflex init. Нам предлагают начать работу с одного
00:01:53из их шаблонов. Но для демо мы выберем самый простой вариант — пустой
00:01:57проект Reflex. После этого откроем проект в редакторе. Если заглянуть в
00:02:02папку reflex_test, всё наше приложение находится в файле reflex_test.py. Мы видим,
00:02:09что там есть секция компонентов RX и класс состояния (State). Запустим reflex run в терминале,
00:02:15чтобы поднять приложение. Оно запускается на порту 3000, и мы видим результат в браузере.
00:02:20Теперь посмотрим, как Reflex управляет состоянием. Добавим простую переменную count.
00:02:25Чтобы изменять её значение, нужно определить функцию. Сразу под
00:02:29переменной count пропишем функцию increment, которая будет увеличивать счетчик на единицу. Также
00:02:34рекомендуется добавить декоратор @rx.event, который включает статическую проверку типов и
00:02:39гарантирует, что обработчики событий получают верные аргументы. Затем добавим
00:02:44простую кнопку в оператор return компонента RX. Она будет отображать счетчик
00:02:48и вызывать функцию increment при нажатии. Reflex поддерживает горячую перезагрузку. Поэтому,
00:02:53если мы сохраним файл и откроем браузер, мы увидим кнопку, которая увеличивает значение
00:02:58при каждом нажатии. Теперь попробуем что-то поинтереснее. Создадим массив элементов
00:03:02в нашем состоянии. В теории мы могли бы отрендерить их списком с помощью обычного
00:03:08инлайнового цикла for. Но это не сработает, так как значение неизвестно на этапе компиляции. Дело в том,
00:03:13что в Reflex фронтенд компилируется в JavaScript-код, который работает в браузере —
00:03:18это называется «время компиляции» (compile time). Бэкенд же остается
00:03:23на Python и работает на сервере во время жизни приложения — это «время выполнения» (runtime).
00:03:27Поэтому мы не можем использовать чистый цикл for внутри рендера компонента, но можем
00:03:32использовать Python-операции вне этого блока. Как же тогда пройтись по элементам в блоке
00:03:37компонента? Для этого нужно определить простую функцию render_item, которая будет
00:03:42отрисовывать элемент, и использовать функцию rx.foreach внутри блока рендеринга,
00:03:47чтобы запустить цикл. Теперь элементы отображаются корректно. То же самое касается
00:03:53условного рендеринга. Мы не можем использовать обычные if-else в блоке return. Вместо
00:03:58этого нужно использовать функцию rx.cond. Теперь, если мы нажмем кнопку
00:04:02более пяти раз, на экране появится наш текст. И последнее — как загружать
00:04:08и отображать данные. Для демо возьмем случайный бесполезный факт из API
00:04:12«random useless facts» и выведем его. Сначала добавим булеву переменную для статуса
00:04:17загрузки и пустую строку для самого факта. Затем определим асинхронную
00:04:22функцию получения данных, которая установит статус загрузки в true. Далее
00:04:27используем библиотеку HTTPX, чтобы получить факт и сохранить его в переменную состояния. Также
00:04:33я добавлю небольшую задержку в одну секунду через asyncio, чтобы мы могли увидеть процесс загрузки
00:04:38в реальном времени. После завершения операции возвращаем статус загрузки в false. Обратите внимание,
00:04:43что мы использовали здесь оператор yield. Если нужно обновить UI несколько раз внутри
00:04:48обработчика событий, мы используем yield для отправки обновлений в рендерер. В данном случае,
00:04:52как только статус загрузки меняется, мы хотим обновить интерфейс. Не забудем импортировать
00:04:57HTTPX и asyncio. Наконец, в функции рендеринга используем простую
00:05:03функцию rx.cond, чтобы показывать спиннер или сам факт в зависимости от состояния. Если мы
00:05:08хотим, чтобы функция срабатывала при каждой загрузке страницы, нужно добавить декоратор к
00:05:12компоненту, который вызовет fetch_data при загрузке. Теперь при обновлении страницы мы
00:05:18видим, как подгружается и отображается случайный факт. И напоследок заглянем
00:05:22в папку .web. Как видите, всё, что мы написали, компилируется и
00:05:27отрисовывается как React-приложение, использующее Vite и Tailwind под капотом.
00:05:33Там даже есть React Router для навигации. Честно говоря, когда я это увидел, я был крайне
00:05:38разочарован. Я думал, они создали какой-то кастомный компилятор JavaScript или что-то оригинальное.
00:05:42Но по факту Reflex — это просто еще один слой абстракции над React. Так что у меня
00:05:47смешанные чувства. С одной стороны, идея единого фулстек-фреймворка на Python,
00:05:53позволяющего писать всё на одном языке, крутая. Но я расстроился, узнав,
00:05:59что внутри это обертка над React, а не нативный Python. Это только всё
00:06:05усложняет, потому что вам приходится учить новую архитектуру и понимать,
00:06:11как Reflex управляет состоянием, не говоря уже о куче граничных случаев. С тем же успехом
00:06:16можно просто использовать React, так как это проверенный временем и надежный фреймворк. Если бы я
00:06:22создавал проект с бэкендом на Python, я бы всё равно выбрал JS-фреймворк для фронтенда.
00:06:28Reflex не убедил меня полностью перейти на Python-фулстек. Но это лишь мое мнение. А
00:06:34что вы думаете о Reflex? Вам нравится идея такого фулстек-фреймворка на Python?
00:06:39Мне очень интересно ваше мнение. И если вам понравилось видео, дайте нам знать,
00:06:44нажав на лайк под роликом. И не забудьте подписаться на наш канал.
00:06:50С вами был Андрис из Better Stack, увидимся в следующих видео!