DEV Community

Cover image for Provider ile State Y├Ânetimi ­čĺź ­čîî ÔťĘ
G├╝lsen Keskin
G├╝lsen Keskin

Posted on • Updated on

Provider ile State Y├Ânetimi ­čĺź ­čîî ÔťĘ

image

Flutter'da state'i , onu kullanan widget'lar─▒n ├╝zerinde tutmak mant─▒kl─▒d─▒r.
Yaln─▒zca ebeveynlerinin olu┼čturma y├Ântemlerinde yeni widget'lar olu┼čturabildi─činiz i├žin, i├žeri─či de─či┼čtirmek istiyorsan─▒z, bunun MyCart'─▒n ├╝st ├Â─česinde veya ├╝st├╝nde ya┼čamas─▒ gerekir.

Flutter'da i├žeri─či her de─či┼čtirdi─činizde yeni bir UI ├Â─česi olu┼čturursunuz. MyCart.updateWith(somethingNew)(Bir y├Ântem ├ža─čr─▒s─▒) yerine MyCart(contents)(bir kurucu) kullan─▒rs─▒n─▒z. Yeni widget'lar─▒ yaln─▒zca ebeveynlerinin olu┼čturma y├Ântemlerinde olu┼čturabilirsiniz

void myTapHandler(BuildContext context) {
  var cartModel = somehowGetMyCartModel(context);
  cartModel.add(item);
}

Widget build(BuildContext context) {
  var cartModel = somehowGetMyCartModel(context);
  return SomeWidget(
     // Sepetin mevcut durumunu kullanarak kullan─▒c─▒ aray├╝z├╝n├╝ bir kez olu┼čturun.   
     // ┬Ě┬Ě┬Ě
  );
}
Enter fullscreen mode Exit fullscreen mode

ChangeNotifier

ChangeNotifier dinleyicilerine de─či┼čiklik bildirimi sa─člayan Flutter SDK'da bulunan basit bir s─▒n─▒ft─▒r. Ba┼čka bir deyi┼čle, bir ┼čey ChangeNotifier ise, de─či┼čikliklerine abone olabilirsiniz.

Provider'da , ChangeNotifier (De─či┼čiklik Bildiricisi), uygulama durumunuzu kaps├╝llemenin bir yoludur. ├çok basit uygulamalar i├žin, tek bir ChangeNotifier kullanabilirsiniz. Karma┼č─▒k olanlarda, birka├ž modele ve dolay─▒s─▒yla birka├ž ChangeNotifier'a sahip olman─▒z gerekir. (Changenotifier'─▒ provider ile birlikte kullanman─▒za gerek yoktur, ancak ├žal─▒┼čmas─▒ kolay bir s─▒n─▒ft─▒r.)

Al─▒┼čveri┼č uygulamas─▒ ├Ârne─čimizde, sepetin durumunu bir ChangeNotifier'da (De─či┼čiklik Bildiricisinde) y├Ânetmek istiyoruz. Onu geni┼čleten yeni bir s─▒n─▒f olu┼čturuyoruz, ┼č├Âyle:

class CartModel extends ChangeNotifier {
  final List<Item> _items = [];

 //Sepetteki ├Â─čelerin de─či┼čtirilemez bir g├Âr├╝n├╝m├╝.
  UnmodifiableListView<Item> get items => UnmodifiableListView(_items);

 //T├╝m kalemlerin ge├žerli toplam fiyat─▒ (t├╝m kalemlerin 42 ABD Dolar─▒ oldu─ču varsay─▒larak)

  int get totalPrice => _items.length * 42;

  // cart from the outside.
  void add(Item item) {
    _items.add(item);
    // Bu ├ža─čr─▒, bu modeli dinleyen widget'lara yeniden olu┼čturmalar─▒n─▒ s├Âyler.
    notifyListeners();
  }

  void removeAll() {
    _items.clear();
    // Bu ├ža─čr─▒, bu modeli dinleyen widget'lara yeniden olu┼čturmalar─▒n─▒ s├Âyler.
    notifyListeners();
  }
}
Enter fullscreen mode Exit fullscreen mode

ChangeNotifier'a ├Âzel olan tek kod notifyListeners() d─▒r. Model, uygulaman─▒z─▒n kullan─▒c─▒ aray├╝z├╝n├╝ de─či┼čtirebilecek ┼čekilde her de─či┼čti─činde bu y├Ântemi ├ža─č─▒r─▒n. Di─čer her ┼čey CartModel'in kendisi ve i┼č mant─▒─č─▒d─▒r.

ChangeNotifier, flutter:foundation'─▒n bir par├žas─▒d─▒r ve Flutter'daki herhangi bir ├╝st d├╝zey s─▒n─▒fa ba─čl─▒ de─čildir. Kolayca test edilebilir (bunun i├žin widget testi kullanman─▒za bile gerek yoktur). ├ľrne─čin, CartModel'in basit bir birim testi:

test('adding item increases total cost', () {
  final cart = CartModel();
  final startingPrice = cart.totalPrice;
  cart.addListener(() {
    expect(cart.totalPrice, greaterThan(startingPrice));
  });
  cart.add(Item('Dash'));
});
Enter fullscreen mode Exit fullscreen mode

ChangeNotifierProvider

ChangeNotifierProvider, soyundan gelenlere bir ChangeNotifier ├Ârne─či sa─člar. Provider paketinden gelir.

ChangeNotifierProvider:'─▒ ona eri┼čmesi gereken widget'lar─▒n ├╝zerine nereye koyaca─č─▒m─▒z─▒ zaten biliyoruz. CartModel s├Âz konusu oldu─čunda bu, hem MyCart hem de MyCatalog'un ├╝zerinde bir yer anlam─▒na gelir.

ChangeNotifierProvider'─▒ gere─činden y├╝kse─če yerle┼čtirmek istemezsiniz (├ž├╝nk├╝ kapsam─▒ kirletmek istemezsiniz). Ancak bizim durumumuzda hem MyCart'─▒n hem de MyCatalog'un ├╝st├╝nde olan tek pencere ├Â─česi MyApp'dir.

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => CartModel(),
      child: const MyApp(),
    ),
  );
}
Enter fullscreen mode Exit fullscreen mode

CartModel'in yeni bir ├Ârne─čini olu┼čturan bir builder tan─▒mlad─▒─č─▒m─▒z─▒ unutmay─▒n. ChangeNotifierProvider, kesinlikle gerekli olmad─▒k├ža CartModel'i yeniden olu┼čturmayacak kadar ak─▒ll─▒d─▒r. Ayr─▒ca, ├Ârne─če art─▒k ihtiya├ž duyulmad─▒─č─▒nda CartModel'de Dispose() i┼člevini otomatik olarak ├ža─č─▒r─▒r.

Birden fazla s─▒n─▒f sa─člamak istiyorsan─▒z, MultiProvider'─▒ kullanabilirsiniz:

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => CartModel()),
        Provider(create: (context) => SomeOtherClass()),
      ],
      child: const MyApp(),
    ),
  );
}
Enter fullscreen mode Exit fullscreen mode

Consumer

Art─▒k CartModel , uygulaman─▒zdaki widget'lara en ├╝stteki ChangeNotifierProvider bildirimi arac─▒l─▒─č─▒yla sa─čland─▒─č─▒ndan, bunu kullanmaya ba┼člayabiliriz.

Bu, Consumer widget'─▒ arac─▒l─▒─č─▒yla yap─▒l─▒r.

return Consumer<CartModel>(
  builder: (context, cart, child) {
    return Text("Total price: ${cart.totalPrice}");
  },
);
Enter fullscreen mode Exit fullscreen mode

Eri┼čmek istedi─čimiz modelin t├╝r├╝n├╝ belirtmeliyiz. Bu durumda, CartModel'i istiyoruz, bu y├╝zden Consumer<CartModel> yaz─▒yoruz. Jenerik (<CartModel>) belirtmezseniz, sa─člay─▒c─▒ paketi size yard─▒mc─▒ olamaz. sa─člay─▒c─▒ t├╝rlere dayan─▒r ve t├╝r olmadan ne istedi─činizi bilmez.

T├╝ketici widget'─▒n─▒n tek gerekli arg├╝man─▒ olu┼čturucudur. Builder, ChangeNotifier de─či┼čti─činde ├ža─čr─▒lan bir i┼člevdir. (Ba┼čka bir deyi┼čle, modelinizde notifyListeners() ├Â─česini ├ža─č─▒rd─▒─č─▒n─▒zda, kar┼č─▒l─▒k gelen t├╝m Consumer ├Â─čelerinin t├╝m builder y├Ântemleri ├ža─čr─▒l─▒r.)

Builder├╝├ž arg├╝manla ├ža─čr─▒l─▒r. ─░lki, her derleme y├Ânteminde de ald─▒─č─▒n─▒z contex'tir (ba─člamd─▒r).

Builder methodunun ikinci arg├╝man─▒, ChangeNotifier ├Ârne─čidir. En ba┼čta istedi─čimiz buydu. Herhangi bir noktada kullan─▒c─▒ aray├╝z├╝n├╝n nas─▒l g├Âr├╝nmesi gerekti─čini tan─▒mlamak i├žin modeldeki verileri kullanabilirsiniz.

├ť├ž├╝nc├╝ arg├╝man, optimizasyon i├žin orada olan child'd─▒r. Consumer'─▒n─▒z─▒n alt─▒nda model de─či┼čti─činde de─či┼čmeyen b├╝y├╝k bir widget alt a─čac─▒n─▒z varsa, onu bir kez olu┼čturabilir ve olu┼čturucudan ge├žirebilirsiniz.

return Consumer<CartModel>(
  builder: (context, cart, child) => Stack(
    children: [
      // Her seferinde yeniden in┼ča etmeden burada SomeExpensiveWidget  kullan─▒n.
      if (child != null) child,
      Text("Total price: ${cart.totalPrice}"),
    ],
  ),
  // Build the expensive widget here.
  child: const SomeExpensiveWidget(),
);
Enter fullscreen mode Exit fullscreen mode

Consumer widget'lar─▒n─▒z─▒ a─čac─▒n m├╝mk├╝n oldu─čunca derinlerine yerle┼čtirmek en iyi uygulamad─▒r. Baz─▒ ayr─▒nt─▒lar de─či┼čti diye kullan─▒c─▒ aray├╝z├╝n├╝n b├╝y├╝k b├Âl├╝mlerini yeniden olu┼čturmak istemezsiniz.

return Consumer<CartModel>(
  builder: (context, cart, child) {
    return HumongousWidget(
      // ...
      child: AnotherMonstrousWidget(
        // ...
        child: Text('Total price: ${cart.totalPrice}'),
      ),
    );
  },
);
Enter fullscreen mode Exit fullscreen mode

Bunun yerine:

//Bunu kullan
return HumongousWidget(
  // ...
  child: AnotherMonstrousWidget(
    // ...
    child: Consumer<CartModel>(
      builder: (context, cart, child) {
        return Text('Total price: ${cart.totalPrice}');
      },
    ),
  ),
);
Enter fullscreen mode Exit fullscreen mode

Provider.of

Bazen, kullan─▒c─▒ aray├╝z├╝n├╝ de─či┼čtirmek i├žin modeldeki verilere ger├žekten ihtiyac─▒n─▒z olmaz, ancak yine de ona eri┼čmeniz gerekir. ├ľrne─čin, ClearCart d├╝─čmesi, kullan─▒c─▒n─▒n sepetteki her ┼čeyi kald─▒rmas─▒na izin vermek ister. Sepetin i├žeri─čini g├Âr├╝nt├╝lemesi gerekmez, sadece clear() y├Ântemini ├ža─č─▒rmas─▒ gerekir.

Bunun i├žin Consumer<Cart Model> kullanabiliriz, ancak bu israf olur. ├çer├ževeden (framework) yeniden olu┼čturulmas─▒ gerekmeyen bir widget'─▒ yeniden olu┼čturmas─▒n─▒ istiyoruz.

Bu kullan─▒m durumu i├žin, listen parametresi false olarak ayarlanm─▒┼č olarak Provider.of'u kullanabiliriz.

Provider.of<CartModel>(context, listen: false).removeAll();

Yukar─▒daki sat─▒r─▒ bir build methodunda kullanmak, notifyListeners ├ža─čr─▒ld─▒─č─▒nda bu widget'─▒n yeniden olu┼čturulmas─▒na neden olmaz.

resource: https://docs.flutter.dev/development/data-and-backend/state-mgmt/simple

Top comments (0)