Статья просвещена тем, кто пишет на стеке React/React Native и хочет освоить новую для себя технологию – Flutter. И нет, мы не будем тут писать приложение на этом фреймворке! Если вы ждете какой-нибудь очередной Todo List – этот материал не для вас.

image

Скорее это очередная история о том, как я перешел на новый фремйворк)

Материал не предполагает собой истину в последней инстанции. Тут описаны лишь те решения, которые я выбрал для себя, и которые мне, имея огромный бэкграунд в React & React Native разработке, было легче всего применить на реальном проекте.

Контекст


Для начала опишу, так сказать, контекст. Появился заказ – написать небольшое (около 15 экранов) кроссплатформенное мобильное приложение. Естественно, начал по привычке делать на React Native. За две недели приложение было реализовано где-то на 80%.

На выходных прочитал на хабре очередную статью от Surf с результатами опроса. И пришла мысль, а почему бы не попробовать? Смогу ли я то что уже написано повторить на новом для себя фреймворке? Решено было потратить выходные на эту попытку. В результате, за следующую неделю были переписаны не только те 80% что были до этого, но и остальные 20. Т.е. срок разработки сократился более чем в два раза!

Плюсы


В первую очередь, плюсом является, скорость верстки. Экраны клепаются ОЧЕНЬ быстро. Линейные градиенты, svg, gif – почти все из коробки. Перекрывающие друг друга компоненты (position: absolute) – вообще никаких проблем. Все то, что вызывало боль в React Native, тут делается по щелчку пальцев. Анимации – это вообще сказка! На один и тот же экран с постоянно анимированными компонентами потрачено в разы меньше времени с Flutter.

Минусы


Ощутимых минусов два. Первый – документация. На русском очень мало. Официальная английская не очень хорошо структурирована, да, она дает много полезных примеров кода, но по общей архитектуре приложения там сложно что-то толковое понять.

Второй минус – пакеты. До сих пор там полный бардак. Выбрать действительно хороший пакет для нужного тебе – не тривиальная задача. Где-то одна фича не работает, где-то другая. Времени на подбор тратится много. Как вариант – дописывать что-то самому, но это когда уже немного освоюсь)

Опыт: хуки


Мое знакомство с React началось еще во времена, когда в нем только-только появились нормальные классы. Сейчас я не представляю его себе без хуков и уже забыл про классы. Для flutter есть замечательная библиотека flutter_hooks, позволяющая привнести привычные хуки в свой проект. Для меня она полностью заменила StatefulWidget. Хуков много, можно писать свои, но чаще всего используются у меня в коде именно useEffect, useState и useMemoized. Для анимаций — useAnimationController.

Может быть это не лучшее решение (готов почитать в комментариях о минусах), но позволяет использовать бэкграунд из React в новом для себя фреймворке. Даже не вижу смысла приводить примеры с кодом — всем React разработчикам это знакомо как «отче наш»!

Опыт: state management


В свое время приходилось работать и с redux, и с mobx, и даже, с экзотикой, типа storeon. Вроде бы оно (redux/mobx) есть и под Flutter, но, честно говоря, не осилил). На мой взгляд там все слишком усложнено по сравнению с тем, что было в React. Можно, конечно, потратить побольше времени и разобраться, но зачем, когда я нашел решение лучше: riverpod.

Библиотека от Remi Rousselet, автора flutter_hooks — естественно, что они обе прекрасно сочетаемы). По сути, она представляет собой доработанный Provider. Просто добавляем в свой runApp(ProviderScope(…)) оберткой над всем остальным и получаем глобальный scope во всем приложении, доступный из любого виджета. Достаточно написать useProvider(providerName) в build методе HookWidget и у нас доступные данные из указанного провайдера.

В библиотеке много вариантов провайдеров, но самые основные это ChangeNotifyProvider и StateNotifyProvider. Всю бизнес логику можно смело выносить из виджетов и переносить в эти провайдеры. Тем более они отлично комбинируются друг с другом и не составит труда получить из одного доступ к методам и данным другого.

Паттерн в применении очень похож на redux ducks подход, который, лично мне, стал ближе всего в мире React. Только «утки» более мелкие получаются. Тут главное помнить, что лучше много маленьких провайдеров которые будет использоваться в разных виджетах, чем один большой для них, потому что перерисовываться будут те виджеты, которые реально были изменены.

Разочарование: web


После ошеломительного (для себя самого) успеха с разработкой мобильного приложения, я, как любой уважающий себя фуллстек, решил пощупать и Flutter for web. Опять же переписав одно из реально работающих корпоративных приложений.

Конечно, flutter web еще в бетте, и все нижеописанное относится именно к бетта версии. Очень надеюсь, что с релизом многое изменится в лучшую сторону. Но тем не менее, тут меня Flutter разочаровал.

Первое что надо знать Flutter Web — это не про сайты, а именно про приложения! Т.е. надо писать точно также, как и под мобильный. Все виджеты такие же. Использовать сторонний JS в коде нельзя. Только обращаться к нему через dart:js. Доступ к html тоже через dart:html. Это разом отсекает почти все что уже сделано в мире web. Хочешь крутую анимацию, которая уже где-то реализована на css+js — нефиг, пиши сам аналог на flutter или используй dart:js что не всегда просто. Безболезненно заюзать готовую JS/css библиотеку не получится.

Второй минус — опять пакеты! Хоть на pub.dev большая часть и отмечена как поддерживающая и web, и android, и ios, но по факту обычно работает либо то, либо другое. Т.е. создать полностью кроссплатформенный код не получится.

Пакеты для web обычно представляют собой обертку над js аналогами. Но почти всегда не успевают за версией того пакета, который оборачивают.

Пример:


Задача — сделать авторизацию через MS и получение данных пользователя.

На старом-добром JS все просто: берем msal и microsoft/microsoft-graph-client — и наслаждаемся результатом.

Во Flutter находим msal_flutter, подключаем… и выясняется что web пакет не поддерживает. Ладно, находим msal_js — это обертка над обычным msal, значит надо его подключить в index.html через старый-добрый тег script. Но если msal уже обновился до 1.4.2 то этот пакет поддерживает максимум 1.3.0!

Ну хорошо, токен мы с горем пополам получили, как быть с данными пользователя? Есть пакет microsoft_graph — документации по нему никакой. Чтобы найти нужный метод надо лезть в код пакета и ковырять там. И выяснить в итоге что там реализовано всего пара для работы с задачами! Находим еще msgraph — так тот вообще единственный метод поддерживает!

Благо что сам протокол там не очень сложный и можно побыстрому написать что-то свое, когда надо работать а не библиотеки писать)

Окружение


Третий и самый огромный минус — невозможность настройки окружения. Flutter web запускается либо в браузере либо в виде веб сервера. Задать порт, на котором оно будет крутиться еще можно через параметры командной строки (что тоже не очень удобно, где конфиг?!) Но как мне запустить его как https с самоподписанным сертификатом? Чтобы при этом и хотрелоад работал и дебаг и прочие фишки которые обычно работают? Алло! Ребята, 2к20 заканчивается, а у вас до сих пор http? Серьезно?!

Вывод


Однозначно, Flutter как фреймворк для кроссплатформенной мобильной разработки, рвет React Native в клочья по всем фронтам. Я доволен, заказчик тоже в восторге — что еще надо?

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

ПС


Еще раз повторю для тех, кто забыл из начала статьи. Описанные мной применяемые решения и выводы — это выводы человека с 1 неделей бэкграунда во Flutter и трехлетним бэкграундом в React. Так что не стоит принимать их за истину в последней инстанции. Готов обсудить в комментариях с гуру, что я сделал не так.