برنامه نویسی

به حداکثر رساندن عملکرد برنامه Flutter با (Async)NotifierProvider، فریز شده و تولید کننده کد Riverpod

به حداکثر رساندن عملکرد برنامه Flutter برای ارائه یک تجربه کاربری یکپارچه بسیار مهم است. به‌عنوان توسعه‌دهندگان نرم‌افزار، ما دائماً به دنبال ابزارهایی هستیم که می‌توانند تجربه کدنویسی ما را افزایش دهند و در عین حال کارایی و کیفیت کد ما را بهبود بخشند. این راهنمای مبتدی بر استفاده از قدرت AsyncNotifierProvider و NotifierProvider از Riverpod، همراه با تولید کننده کد Riverpod، برای مدیریت کارآمد حالت تمرکز دارد. با ترکیب این ابزارها، می‌توانید ارائه‌دهندگان را سریع‌تر تولید کنید، فرآیند ارسال ویژگی ref را ساده‌تر کنید و اشکال‌زدایی را ساده کنید. این راهنما شامل مثال‌های ساده‌ای است که نشان می‌دهد چگونه از این ارائه‌دهندگان در پروژه خود استفاده کنید و از مزایای تولیدکننده‌های کد فریز شده و ریورپاد استفاده کنید.

پیش نیازها

  • دانش پایه دارت

  • درک پایه ای از فلاتر و مدیریت دولتی.

  • یک ویرایشگر کد (اندروید استودیو یا VScode توصیه می شود)

  • یک دستگاه تلفن همراه یا شبیه ساز برای ساخت.

  • شما اولین مقاله این مجموعه را خوانده اید یا حداقل دانش اولیه ای از نحوه کار ریورپاد دارید 👇🏽

محدوده این آموزش

در این آموزش به موارد زیر می پردازیم:

  • مثال هایی برای نشان دادن اجرای Notifier و AsyncNotifier Provider.

  • نحوه استفاده از ابزارهای تولید کد مانند فریز شده و تولید کننده کد Riverpod.

  • نحوه استفاده AsyncValue برای رسیدگی به وضعیت بارگذاری

  • نحوه استفاده copyWith هنگام کار با یک کلاس تغییرناپذیر.

نصب وابستگی ها

اول، شما باید به خود برسید pubspec.yaml و بسته های زیر را اضافه کنید

dependencies:
  flutter_riverpod: ^2.1.3
  riverpod_annotation: ^1.1.1
  freezed_annotation: ^2.2.0
  freezed: ^2.3.2

dev_dependencies:
  build_runner:
  riverpod_generator: ^1.1.1
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس اجرا کنید flutter pub get

شما با موفقیت وابستگی های لازم را به پروژه خود اضافه کرده اید.

چرا از ابزارهای تولید کد استفاده کنیم؟

اگر انتخاب کنید که بدون ابزارهای تولید کد کار کنید، ارائه دهندگان Riverpod شما همچنان کاملاً کاربردی خواهند بود. با این حال، Riverpod استفاده از ابزارهای تولید کد را به شدت توصیه می کند. تولید کد از ابزاری برای تولید کد استفاده می کند. در دارت، پس از اضافه کردن نحو تولید کد و کامپایل، کد شما به طور خودکار تولید می شود. انجام این کار باعث صرفه جویی در زمان و انرژی شما می شود که برای نوشتن آن کد استفاده می کردید، به خصوص زمانی که روی یک پروژه بزرگ کار می کنید و نیاز به انجام مکرر آن وظایف دارید. تولید کد به جلوگیری از خطاهایی که ممکن است هنگام انجام مکرر یک کار اتفاق بیفتد کمک می کند. اشکال زدایی را بهتر می کند و به طور کلی زندگی شما را آسان تر می کند.

مولد کد فریز شده

Freezed یک بسته تولید کد است که به شما کمک می کند تا کلاس های داده را با دارت ایجاد کنید. با استفاده از Freezed می‌توانید مدل‌ها، اتحادیه‌ها و موارد دیگر تولید کنید. Freezed به شما امکان می دهد به جای نوشتن خطوط طولانی کد که ممکن است مستعد خطا باشد، روی تعریف کلاس داده خود تمرکز کنید.

درباره کارهایی که می توانید با Freezed انجام دهید بیشتر بخوانید.

مولد کد ریورپاد

با بسته تولید کد Riverpod، اکنون اعلام ارائه دهندگان آسان تر است. دیگر نیازی نیست که ارائه دهندگان خود را به صورت دستی بنویسید یا تعجب کنید که کدام ارائه دهنده خاص برای مورد استفاده شما مناسب است.

تنها کاری که باید انجام دهید این است که برای تعریف مولد کد Riverpod خود، دستور زبان را دنبال کنید و کد خود را حاشیه نویسی کنید، سپس با build_runner شما می توانید تمام ارائه دهندگان خود را ایجاد کنید.

به عنوان مثال، این سینتکس تولید کد برای این ارائه دهندگان مختلف Riverpod است

برای ارائه دهندگان:

@riverpod
int foo(FooRef ref) => 0;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای FutureProviders:

@riverpod
Future<int> foo(FooRef ref) async {
  return 0;
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای State Providers

@riverpod
class Foo extends _$Foo {
  @override
  int build() => 0;
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

می توانید متوجه شوید که الگویی برای ایجاد ارائه دهندگان وجود دارد. هنگامی که سینتکس صحیح را قرار دادید، می توانید ارائه دهندگان را دقیقاً مانند آن ایجاد کنید.

به ارائه دهنده اطلاع دهید

Riverpod 2.0 با اضافه شدن دو نوع ارائه دهنده جدید، NotifierProvider و AsyncNotifierProvider عرضه شد. Riverpod توصیه می کند که به جای ارائه دهندگان ChangeNotifier و StateNotifier از NotifierProvider استفاده کنید، بنابراین ما روی این دو تمرکز می کنیم.

NotifierProvider برای گوش دادن و افشای یک Notifier استفاده می شود. یک Notifier حالتی را نشان می دهد که می تواند در طول زمان تغییر کند.

بیایید یک مثال ساده را در نظر بگیریم 👇🏽

ما یک مولد رشته تصادفی با دو دکمه می سازیم، یکی برای تولید یک رشته جدید و دیگری برای پاک کردن کل لیست رشته ها. در این مثال، ما از مولد کد Riverpod نیز استفاده خواهیم کرد.

  • ابتدا با استفاده از حاشیه نویسی Riverpod و نحو کد زیر، یک NotifierProvider ایجاد می کنیم. ما همچنین توابع اضافه کردن یک رشته تصادفی و پاک کردن لیست رشته ها را اضافه می کنیم. با مشخص کردن با نام فایلی که باید تولید شود را اضافه می کنیم part همانطور که در کد مشاهده می شود.

    توجه: نام فایلی که باید تولید شود با نام فایل فعلی که روی آن کار می کنید یکسان است. هنگام مشخص کردن آن با part باید اضافه کنید .g.dart همانطور که فایل های تولید شده توسط Riverpod نامگذاری می شوند.

import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'notifier_list_provider.g.dart';

@riverpod
class RandomStrNotifier extends _$RandomStrNotifier{
  @override
  List<String> build() {
    return [];
  }
//using Dart's spread operator we create a new copy of the list
  void addString(String randomStr){
    state = [...state, randomStr];
  }

  void removeStrings(){
    state = [];
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

از کد ما، می توانیم ببینیم که RandomStrNotifier یک لیست خالی برمی گرداند، سپس دو تابع را اضافه کردیم تا به لیست اضافه شود و لیست پاک شود. NotifierProvider و AsyncNotifierProvider از حالت تغییرناپذیر پشتیبانی می کنند، چون وضعیت ما تغییرناپذیر است، نمی توانیم بگوییم state.add یا state.remove. بنابراین ما یک کپی جدید از لیست ایجاد می کنیم. state برای به روز رسانی حالت رابط کاربری استفاده می شود.

برای اجرای کد مولد این دستور را در ترمینال اجرا کنید:

flutter pub run build_runner watch --delete-conflicting-outputs
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پس از اجرای موفقیت آمیز، می توانید فایل ارائه دهنده تولید شده خود را در تب پروژه خود، در ویرایشگر کد خود مشاهده کنید.

فایل تولید شده توسط Riverpod

از تصویر بالا می توانید ببینید که فایل تولید شده چگونه خواهد بود.

توجه: در صورت دریافت خطا Could not find a file named "pubspec.yaml" in "C:\Users\… سپس اجرا کنید dart pub get دستور روی ترمینال شما

  • در ادامه، بیایید این ارائه دهنده و توابع را به رابط کاربری خود اضافه کنیم
Widget build(BuildContext context, ref) {
        // rebuid the widget when there is a change
    List<String> randomStrList = ref.watch(randomStrNotifierProvider);
    final random = Random();
    return Scaffold(
      appBar: AppBar(
        title: const Text("RiverPod Notifier Example App"),
        backgroundColor: Colors.brown,
      ),
      body: SingleChildScrollView(
        child: Column(
          children: [
            Column(
              children: [
                                //map to a list
                ...randomStrList.map((string) =>
                    Container(
                      alignment: Alignment.center,
                      margin: const EdgeInsets.only(bottom: 10,top: 5),
                      height: 30,
                        width: 300,
                        color: Colors.brown,
                        child: Text(string.toString(),
                          style: const TextStyle(
                            color: Colors.white
                          ),
                        )))
              ],
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                ElevatedButton.icon(
                  icon: const Icon(Icons.add),
                  label: const Text('Generate'),
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.brown, // Background color
                  ),
                  onPressed: () {
                                    //add string to list function
                    ref.read(randomStrNotifierProvider.notifier).addString("This is the "
                        "random String ${5  + random.nextInt( 1000 + 1 - 5)}");
                  },
                ),

                ElevatedButton.icon(
                  icon: const Icon(Icons.clear),
                  label: const Text('Clear'),
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.brown, // Background color
                  ),
                  onPressed: () {
                                    //clear list function
                    ref.read(randomStrNotifierProvider.notifier).removeString();
                  },
                )
              ],
            )
          ],
        ),
      ),
    );
  }
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همانطور که می بینید مولد کد Riverpod، یک تطابق ایجاد کرد randomStrNotifierProvider

وقتی برنامه را اجرا می کنید باید به این شکل باشد👇🏽

مثال ارائه دهنده اعلان کننده

AsyncNotifierProvider

AsyncNotifierProvider برای گوش دادن و افشای یک asyncNotifier استفاده می شود. AsyncNotifier یک اعلان کننده است که به صورت ناهمزمان مقداردهی اولیه می شود.

بیایید به مثال شیرجه بزنیم

ما در حال ساخت یک برنامه ساده خواهیم بود که لیستی از محصولات را پس از مدت زمان 3 ثانیه با یک دکمه برای پاک کردن لیست محصولات بارگیری می کند.

  • ابتدا از ابزار Freezed code generator برای ایجاد کلاس محصول خود استفاده می کنیم. سپس با استفاده از copyWith روش ما اشیاء محصول را ایجاد خواهیم کرد که در لیست ما قرار خواهند گرفت. با مشخص کردن با نام فایلی که باید تولید شود را اضافه می کنیم part همانطور که در کد مشاهده می شود. نام فایل تولید شده نام فعلی فایل شما و .freezed.dart نام گذاری فایل های فریز شده به این صورت است.
import 'package:freezed_annotation/freezed_annotation.dart';
//replace with part 'name_of_your_file.freezed.dart';
part 'async_notifier_list_provider.freezed.dart';

@freezed
class Product with _$Product{
  const Product._();
  const factory Product({
    String? name,
    String? description,

  }) = _Product;

}

  const Product _product1 =  Product(name: "Dart course for beginners",
                            description: "This is course will make you a dart star");
  final Product _product2 = _product1.copyWith(description: "This course will make you a pro");
  final Product _product3 = _product1.copyWith(name: "Ultimate Dart course for beginners");

final products = [
              _product1,
              _product2,
              _product3,
];
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما می توانیم این دستور را در ترمینال اجرا کنیم تا فایل فریز شده را تولید کنیم

flutter pub run build_runner watch --delete-conflicting-outputs
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

فایل ایجاد شده فریز شده

تصویر بالا نشان می دهد که فایل فریز شده تولید شده چگونه به نظر می رسد.

ما استفاده کردیم copyWith روشی برای ایجاد اشیاء جدیدی از محصول که به لیست اضافه کردیم. را copyWith متد برای برگرداندن یک شی جدید با همان ویژگی های اصلی استفاده می شود، اما با مقادیری که شما مشخص کرده اید، هنگام کار با ساختارهای تغییرناپذیر مانند Freezed استفاده می شود.

اکنون ما به جلو می رویم و کلاس ارائه دهنده Riverpod خود را اضافه می کنیم، که پس از 3 ثانیه لیست محصولات را دریافت می کند. ما همچنین عملکرد را اضافه می کنیم تا لیست محصولات را نیز پاک کنیم.

//replace with part 'name_of_your_file.g.dart';
part 'async_notifier_list_provider.g.dart';

@riverpod
class AsyncProducts extends _$AsyncProducts {
  Future<List<Product>> _fetchProducts() async {
    await Future.delayed(const Duration(seconds: 3));
    return products;
  }

  @override
  FutureOr<List<Product>> build() async {
    return _fetchProducts();
  }

  Future<void>clearProducts()async {
    state = const AsyncValue.loading();
    state = await AsyncValue.guard(() async{
      await Future.delayed(const Duration(seconds: 3));
      return [];
    });
  }

}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

asyncNotifierProvider لیست آینده محصولات را برمی گرداند. برای تغییر رابط کاربری، اکنون آن را ایجاد می کنیم clearProducts تابع، با استفاده از AsyncValue class ما می توانیم به راحتی بارگذاری، وضعیت خطا و وضعیت داده را مدیریت کنیم.

نگاه کردن به AsyncValue کلاس، AsyncValue.guard برای تبدیل آینده‌ای که ممکن است شکست بخورد به چیزی امن برای خواندن استفاده می‌شود، توصیه می‌شود به جای تلاش و گرفتن بلوک‌ها از آن استفاده کنید. هر دو حالت داده و خطا را مدیریت می کند.

در مرحله بعد، این دستور را در ترمینال اجرا کنید تا کد Freezed و Riverpod لازم را ایجاد کنید

flutter pub run build_runner watch --delete-conflicting-outputs
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

بیایید این ارائه دهنده و عملکرد را به رابط کاربری خود اضافه کنیم

Widget build(BuildContext context, WidgetRef ref) {
    final productProvider = ref.watch(asyncProductsProvider);
    return Scaffold(
        appBar: AppBar(
            title: const Text("AsyncNotifier"),
            actions: [
              IconButton(
                icon: const Icon(
                  Icons.clear,
                  color: Colors.white,
                ),
                onPressed: () {
                  ref.read(asyncProductsProvider.notifier).clearProducts();
                },
              )
            ]
        ),

      body: Container(
        child: productProvider.when(
          data: (products)=> ListView.builder(
              itemCount: products.length,
              itemBuilder: (context, index){
                return Padding(
                  padding: const EdgeInsets.only(left: 10,right: 10,top: 10),
                  child: Card(
                    color: Colors.blueAccent,
                    elevation: 3,
                    child: ListTile(
                      title: Text("${products[index].name}",style: const TextStyle(
                          color: Colors.white,  fontSize: 15)),
                      subtitle: Text("${products[index].description}",style: const TextStyle(
                          color: Colors.white,  fontSize: 15)),
                    ),
                  ),
                );
              }),
          error: (err, stack) => Text("Error: $err",style: const TextStyle(
              color: Colors.white,  fontSize: 15)),
          loading: ()=> const Center(child: CircularProgressIndicator(color: Colors.blue,)),
        ),
      ),
    );
  }
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در اینجا ما می توانیم آن را با تماس مشاهده کنیم ref.watch می‌توانیم به ارائه‌دهنده خود دسترسی پیدا کنیم، سپس تابع محصول شفاف را به آن اضافه می‌کنیم onPressed با تماس ref.read. اکنون می‌توانیم با استفاده از حالت‌های مختلف پاسخ مدیریت کنیم productProvider.when

وقتی برنامه را اجرا می کنید باید به این شکل باشد👇🏽

مثال ارائه دهنده AsyncNotifier

خلاصه

ما به پایان این آموزش رسیدیم. در اینجا آموختیم که:

  • NotifierProvider به یک اعلان کننده گوش می دهد و در معرض نمایش قرار می دهد، زمانی که تغییری در وضعیت وجود دارد، به طور خودکار UI را به روز می کند. AsyncNotifierProvider برای گوش دادن و افشای اعلان کننده ای که به طور ناهمزمان مقداردهی اولیه شده است استفاده می شود.

  • با استفاده از ابزارهای تولید کد مانند تولیدکننده کد فریز شده و ریورپاد، می‌توانیم به راحتی داده‌ها و کلاس‌های ارائه‌دهنده را با کد بسیار کم تولید کنیم.

  • متد copyWith برای ایجاد یک شی جدید اما با مقادیری که شما مشخص کرده اید، هنگام کار با کلاس های تغییرناپذیر استفاده می شود.

  • در نهایت، کلاس AsyncValue برای مدیریت کارآمد داده ها، بارگذاری و حالت های خطا استفاده می شود.

نتیجه

تبریک می گوییم، شما با موفقیت یاد گرفتید که چگونه از جدیدترین ارائه دهندگان Riverpod، NotifierProvider و AsyncNotifierProvider برای مدیریت وضعیت، نحوه استفاده از ابزارهای تولید کد برای تولید کد، و نحوه استفاده از روش copyWith و کلاس AsyncValue استفاده کنید. اگر از این مقاله لذت بردید، بهتر است واکنش نشان دهید و برای مطالب بیشتر من را دنبال کنید. اگر سؤالی دارید یا هر گونه خطایی دارید، لطفاً بازخورد خود را ارسال کنید.

منابع

Riverpod Docs

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا