Шаблон Riverpod: упрощаем работу с состоянием приложения
Привет, разработчики Flutter! 👋 Сегодня мы рассмотрим полезный совет по использованию Riverpod - популярной библиотеки для управления состоянием приложения. 📈
Проблема: при использовании Riverpod часто приходится писать повторяющийся код, например,
Решение: использование расширений Dart для создания удобных шорткатов. 🔥
Эти расширения позволяют легко получать экземпляр
Пример использования:
Такой подход делает код чище и читабельнее. 📚
Оцените новую рубрику и напишите в комментариях, насколько она вам полезна! 🤔
Все подобные новости можно найти по хэштегу #FlutterPulseTips 👍
#flutter #dart #flutterpulse #FlutterPulseTips #Riverpod #StateManagement #FlutterTips #MobileDevelopment #CodingTips
Привет, разработчики Flutter! 👋 Сегодня мы рассмотрим полезный совет по использованию Riverpod - популярной библиотеки для управления состоянием приложения. 📈
Проблема: при использовании Riverpod часто приходится писать повторяющийся код, например,
ref.read(myProvider).xxx
. Это может быть утомительно и привести к ошибкам. 😩Решение: использование расширений Dart для создания удобных шорткатов. 🔥
extension UserSessionRepositoryProvider on Ref {
UserSessionRepository get userSessionRepository =>
read(userSessionRepositoryProvider);
UserSessionRepository get userSessionRepository$ =>
watch(userSessionRepositoryProvider);
}
Эти расширения позволяют легко получать экземпляр
UserSessionRepository
, используя ref.userSessionRepository
или следить за его изменениями с помощью ref.userSessionRepository$
. 🔄Пример использования:
Future<UserSession> startSession({
required Session session,
}) async {
final activeSession = await ref.userSessionRepository
.getActiveSession(idOrThrow);
if (activeSession != null) {
throw AlreadyRunningSessionException();
}
return ref.userSessionRepository.start(
idOrThrow,
UserSession.fromSession(session),
);
}
Такой подход делает код чище и читабельнее. 📚
Оцените новую рубрику и напишите в комментариях, насколько она вам полезна! 🤔
Все подобные новости можно найти по хэштегу #FlutterPulseTips 👍
#flutter #dart #flutterpulse #FlutterPulseTips #Riverpod #StateManagement #FlutterTips #MobileDevelopment #CodingTips
👍3
Flutter совет: шаблон RevenueCat
Вот несколько методов расширения, чтобы упростить работу с пакетом RevenueCat:
Получение периода подписки продукта в виде Duration
Получение количества пробных дней для продукта
Получение списка характеристик из метаданных RevenueCat в зависимости от языка пользователя
Оцените новую рубрику и напишите своё мнение! 👍💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #RevenueCat #boilerplate #mobiledevelopment #appdevelopment #codingtips
Вот несколько методов расширения, чтобы упростить работу с пакетом RevenueCat:
Получение периода подписки продукта в виде Duration
@override
Duration get duration => switch (revenueCatPackage.storeProduct.subscriptionPeriod) {
'P1W' => const Duration(days: 7),
'P1M' => const Duration(days: 30),
'P3M' => const Duration(days: 90),
'P6M' => const Duration(days: 180),
'P1Y' => const Duration(days: 365),
_ => Duration.zero,
};
Получение количества пробных дней для продукта
@override
int? get trialDays {
final introductory = revenueCatPackage.storeProduct.introductoryPrice;
if (introductory == null) {
return null;
}
if (introductory.price == 0) {
final unit = introductory.periodUnit;
switch (unit) {
case PeriodUnit.day:
return introductory.periodNumberOfUnits;
case PeriodUnit.week:
return introductory.periodNumberOfUnits * 7;
case PeriodUnit.month:
return introductory.periodNumberOfUnits * 30;
case PeriodUnit.year:
return introductory.periodNumberOfUnits * 365;
default:
return null;
}
}
return null;
}
Получение списка характеристик из метаданных RevenueCat в зависимости от языка пользователя
@override
List<String>? get features {
final locale = LocaleSettings.currentLocale.languageCode;
if (revenueCatOffer.metadata[locale] == null) {
return null;
}
final data = revenueCatOffer.metadata[locale]! as Map<Object?, Object?>;
final featurerObj = data["features"]! as List<Object?>;
return featurerObj.map((e) => e! as String).toList();
}
Оцените новую рубрику и напишите своё мнение! 👍💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #RevenueCat #boilerplate #mobiledevelopment #appdevelopment #codingtips
🔥1
Делегирование дизайна виджета
Привет, Flutter-разработчики! 👋 Сегодня мы рассмотрим полезный паттерн проектирования - делегирование дизайна виджета с использованием широко известного паттерна builder. 📈
Когда это полезно? 🤔
Вы создаете виджет списка радиокнопок или чекбоксов, например. И вы не хотите предоставлять дизайн каждого элемента списка. В таком случае вы создаете Item builder, который будет делегировать создание дочерних элементов. 📝
В этом примере мы используем OptionBuilder для делегирования построения элементов списка. Это позволяет нам создать гибкий и переиспользуемый виджет. 🔄
Оцените новую рубрику и напишите в комментариях, что вы думаете о ней! 💬 Все подобные новости можно найти по хэштегу #FlutterPulseTips. 👀
#flutter #dart #flutterpulse #FlutterPulseTips #refactoring #widgetdesign #builderpattern #mobiledevelopment #codingtips
Привет, Flutter-разработчики! 👋 Сегодня мы рассмотрим полезный паттерн проектирования - делегирование дизайна виджета с использованием широко известного паттерна builder. 📈
Когда это полезно? 🤔
Вы создаете виджет списка радиокнопок или чекбоксов, например. И вы не хотите предоставлять дизайн каждого элемента списка. В таком случае вы создаете Item builder, который будет делегировать создание дочерних элементов. 📝
// Определяем тип OptionBuilder для построения элемента из ключа и состояния выбранности
typedef OptionBuilder = Widget Function(String key, bool selected);
// Определяем тип OnValidate для функции валидации
typedef OnValidate = void Function(String? key);
class RadioQuestion extends ConsumerStatefulWidget {
// ...
final OptionBuilder optionBuilder; // Делегируем построение элемента списка
final OnOptionIdSelected? onOptionIdSelected;
final OnValidate? onValidate;
const RadioQuestion({
super.key,
required this.optionBuilder,
this.onOptionIdSelected,
this.onValidate,
// ...
});
@override
ConsumerState<RadioQuestion> createState() => _RadioQuestionState();
}
class _RadioQuestionState extends State<RadioQuestion> {
int? _selectedIndex;
@override
void initState() {
_selectedIndex = widget.initialSelectedIndex;
super.initState();
}
@override
Widget build(BuildContext context) {
return List.generate(
widget.itemCount,
(index) => widget.optionBuilder(widget.keys[index], _selectedIndex == index),
);
}
}
В этом примере мы используем OptionBuilder для делегирования построения элементов списка. Это позволяет нам создать гибкий и переиспользуемый виджет. 🔄
Оцените новую рубрику и напишите в комментариях, что вы думаете о ней! 💬 Все подобные новости можно найти по хэштегу #FlutterPulseTips. 👀
#flutter #dart #flutterpulse #FlutterPulseTips #refactoring #widgetdesign #builderpattern #mobiledevelopment #codingtips
👏4❤1
Заменить код типа на объединенный тип
Удаление кода типа из вашего класса с помощью объединенного типа
Представьте, что у вас есть класс, который ведёт себя по-разному в зависимости от своего состояния. Вместо того, чтобы использовать перечисления (enum) и конструкции
Было:
Стало:
Использование:
Преимущества:
• Инкапсуляция кода типа в отдельные классы
• Для каждого типа создается свой подкласс
• Разная логика для разных типов без использования
• Код становится более читаемым и тестируемым
Оцените новую рубрику! 💡📱 Ваши отзывы нам очень важны! 😊
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #Refactoring #CodingTips #SoftwareDevelopment #ProgrammingTips
Удаление кода типа из вашего класса с помощью объединенного типа
Представьте, что у вас есть класс, который ведёт себя по-разному в зависимости от своего состояния. Вместо того, чтобы использовать перечисления (enum) и конструкции
switch
для определения поведения, вы можете использовать новую возможность Dart 3 — sealed классы. Это делает код чище, безопаснее и проще в поддержке.Было:
enum DocumentType {
pdf,
doc,
markdown,
}
class Document {
final String name;
final DocumentType type;
Document({
required this.name,
required this.type,
});
void write(String newLine) {
switch (type) {
case DocumentType.pdf:
// предположим, что у нас есть библиотека для pdf
break;
case DocumentType.doc:
// предположим, что у нас есть библиотека для doc
break;
case DocumentType.markdown:
// предположим, что у нас есть библиотека для markdown
break;
}
}
}
Стало:
sealed class DocumentSealed {
final String name;
DocumentSealed({required this.name});
}
class PdfDocument extends DocumentSealed {
PdfDocument({required super.name});
void write(String newLine) {
// используем библиотеку для pdf
}
}
class DocDocument extends DocumentSealed {
DocDocument({required super.name});
void write(String newLine) {
// используем библиотеку для doc
}
}
class MarkdownDocument extends DocumentSealed {
MarkdownDocument({required super.name});
void write(String newLine) {
// используем библиотеку для markdown
}
}
Использование:
class Widget extends StatelessWidget {
final DocumentSealed document;
const Widget({super.key, required this.document});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
switch (document) {
case PdfDocument _:
document.write('Hello World');
case DocDocument _:
document.write('Hello World');
case MarkdownDocument _:
document.write('Hello World');
}
},
child: Text(document.name),
);
}
}
Преимущества:
• Инкапсуляция кода типа в отдельные классы
• Для каждого типа создается свой подкласс
• Разная логика для разных типов без использования
switch
• Код становится более читаемым и тестируемым
Оцените новую рубрику! 💡📱 Ваши отзывы нам очень важны! 😊
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #Refactoring #CodingTips #SoftwareDevelopment #ProgrammingTips
Делегирование дизайна виджета с помощью Фабрик
Delegate widget design with Factories
При создании выбираемого списка элементов, например, вы можете создать фабрику радиокнопок или чекбоксов. Фабрики позволяют определить готовый дизайн или поведение виджетов заранее.
Когда это полезно?
Вы создаете выбираемый список элементов. Вы можете создать фабрику радиокнопок или чекбоксов.
Пример реализации:
1. Определите абстрактный класс фабрики, например,
2. Создайте конкретные реализации фабрики, такие как
3. Определите статические экземпляры фабрик для дальнейшего использования:
4. Используйте фабрику для построения части вашего виджета:
Это позволяет создавать готовые функции построения. Разработчики могут создавать свои собственные фабрики, а также использовать предустановленные.
Оцените новую рубрику и напишите своё мнение! 🤔💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #WidgetDesign #Factories #Refactoring #CodingTips #UI/UX
Delegate widget design with Factories
При создании выбираемого списка элементов, например, вы можете создать фабрику радиокнопок или чекбоксов. Фабрики позволяют определить готовый дизайн или поведение виджетов заранее.
Когда это полезно?
Вы создаете выбираемый список элементов. Вы можете создать фабрику радиокнопок или чекбоксов.
Пример реализации:
1. Определите абстрактный класс фабрики, например,
SelectableFactory
:
abstract class SelectableFactory {
const SelectableFactory();
@factory
Widget create({
final String title,
final bool selected
});
}
2. Создайте конкретные реализации фабрики, такие как
SelectableRadioFactory
:
class _SelectableRadioFactory extends SelectableFactory {
@override
Widget create({
final String title,
final bool selected
}) {
// Создайте ваш виджет здесь
return ListTile(...);
}
}
3. Определите статические экземпляры фабрик для дальнейшего использования:
abstract class SelectableFactory {
static const SelectableFactory radio = _SelectableRadioFactory();
static const SelectableFactory checkbox = _SelectableCheckBoxFactory();
...
}
4. Используйте фабрику для построения части вашего виджета:
AnchoredHelper(
title: const Text(
'Нажми чтобы увеличить',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 32,
),
),
widgetFactory: AnchoredCircleHoleHelper.anchorFactory,
);
Это позволяет создавать готовые функции построения. Разработчики могут создавать свои собственные фабрики, а также использовать предустановленные.
Оцените новую рубрику и напишите своё мнение! 🤔💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #WidgetDesign #Factories #Refactoring #CodingTips #UI/UX
👍1
Обработка ошибок с Future
Catch them all 🎯
Неправильная функция
Неправильный способ обработки
catchError перехватывает ошибку, но не возвращает её. Поэтому
Правильный способ обработки
Лучше обрабатывать ошибки в колбэке
Цепочка нескольких Future и обработка ошибок
Ошибка передаётся в последний
Или обработка ошибок через try-catch с await
Оцените новую рубрику! 👍💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #Future #ErrorHandling #FlutterTips #MobileDev #CodingTips
Catch them all 🎯
Неправильная функция
Future<void> functionInError() async {
throw "I am failing"; // Выбрасываем ошибку
}
Неправильный способ обработки
functionInError()
.catchError((err) => print("error catched")) // Перехватываем ошибку
.then(
(value) => print("success"), // Успешное выполнение
onError: (err) => print("I failed"), // Обработка ошибки
);
// Результат:
// error catched
// success
catchError перехватывает ошибку, но не возвращает её. Поэтому
then
выведет success
вместо "I failed".Правильный способ обработки
functionInError()
.catchError((err) {
print("error catched"); // Печатаем сообщение об ошибке
throw err; // Пробрасываем ошибку дальше
})
.then(
(value) => print("success"), // Успешное выполнение
onError: (err) => print("I failed"), // Обработка ошибки
);
// Результат:
// error catched
// I failed
Лучше обрабатывать ошибки в колбэке
onError
. Но если хотите цеплять функции друг за другом, не забудьте пробросить ошибку дальше.Цепочка нескольких Future и обработка ошибок
void main() {
functionInError()
.then((res) => workingFuture()) // Продолжаем цепочку
.then((res) => print("ended")) // Завершаем цепочку
.onError((err) => print("error catched")); // Обрабатываем ошибку
}
Future<void> functionInError() async {
throw "I am failing"; // Выбрасываем ошибку
}
Future<void> workingFuture() async {
print("working future"); // Печатаем сообщение о работе
}
// Результат:
// error catched
Ошибка передаётся в последний
onError
.Или обработка ошибок через try-catch с await
main() async {
try {
await functionInError(); // Ждём завершения функции
} catch (err) {
print("I failed"); // Обрабатываем ошибку
}
}
Оцените новую рубрику! 👍💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #Future #ErrorHandling #FlutterTips #MobileDev #CodingTips
👍1