Asosiy kontentga o‘tish
Innovialabs

Flutter’da holatni boshqarish: Provider, Riverpod yoki BLoC

Chuqur4 daq

Qisqacha

Provider kichik ilovalar uchun mos, Riverpod ko‘pchilik yangi loyihalar uchun oqilona standart tanlov, BLoC esa qat’iy qoidalar va kuzatiladigan hodisalar oqimi kerak bo‘lgan katta jamoalarda o‘zini oqlaydi.

Qisqa javob

Uchala yondashuv ham bitta vazifani hal qiladi: ma’lumotlarni vidjetlardan tashqarida saqlash va ular o‘zgarganda interfeysni qayta chizish. Farq — qat’iylik darajasida va bu qat’iylikning narxida.

  • Provider — eng sodda, InheritedWidget ustidagi yupqa qatlam. Kichik ilovalar va prototiplar uchun yaxshi.
  • Riverpod — o‘sha muallifdan, lekin BuildContext’ga bog‘liq emas, ko‘p xatolarni kompilyatsiya bosqichida ushlaydi va testlarda almashtirishni osonlashtiradi. Oqilona standart tanlov.
  • BLoC — holat faqat hodisalar yoki Cubit metodlari orqali o‘zgaradi. Kod ko‘proq, ammo katta jamoalar uchun bashorat qilinadigan arxitektura.

Bitta vidjetga tegishli lokal holat (ro‘yxat ochiqmi, maydonga nima yozilgan) uchun bularning hech biri kerak emas — setState yetarli.

Kodda qanday ko‘rinadi

Bitta vazifa — xaridlar savati — uch xil usulda.

Provider va ChangeNotifier:

class CartModel extends ChangeNotifier {
  final List<Item> _items = [];
  List<Item> get items => List.unmodifiable(_items);

  void add(Item item) {
    _items.add(item);
    notifyListeners();
  }
}

// ilova ildizi
ChangeNotifierProvider(create: (_) => CartModel(), child: const App());

// vidjet ichida
final count = context.watch<CartModel>().items.length;

Riverpod va Notifier:

final cartProvider =
    NotifierProvider<CartNotifier, List<Item>>(CartNotifier.new);

class CartNotifier extends Notifier<List<Item>> {
  @override
  List<Item> build() => [];

  void add(Item item) => state = [...state, item];
}

// ConsumerWidget ichida
final items = ref.watch(cartProvider);
ref.read(cartProvider.notifier).add(item);

BLoC yengil ko‘rinishda — Cubit:

class CartCubit extends Cubit<List<Item>> {
  CartCubit() : super(const []);

  void add(Item item) => emit([...state, item]);
}

BlocBuilder<CartCubit, List<Item>>(
  builder: (context, items) => Text("${items.length}"),
);

To‘liq Bloc hodisa klasslari (ItemAdded, ItemRemoved) va on<Event> ishlovchilarini qo‘shadi. Kod ko‘payadi, lekin holatning har bir o‘zgarishi nomga ega bo‘ladi va loglarda oson kuzatiladi.

Asosiy mezonlar bo‘yicha taqqoslash

MezonProviderRiverpodBLoC
O‘rganish qiyinligiPastO‘rtaO‘rta–yuqori
Shablon kodMinimalBirozEng ko‘p
BuildContext’ga bog‘liqlikHaYo‘qHa (blokka murojaat uchun)
Provayder topilmasa xatoIshlash vaqtidaOldinroq aniqlanadiIshlash vaqtida
Test qilishModel klassi to‘g‘ridan-to‘g‘riProviderContainer va almashtirishlarbloc_test, holatlar ketma-ketligi
Asinxron ma’lumotQo‘ldaTayyor FutureProvider, AsyncValueHodisalar va yuklanish holatlari
Jamoa hajmi1–3 dasturchiIstalgan, kelishuvlar bilanKatta jamoalar, qat’iy jarayon

Test qilish qulayligi

Provider. ChangeNotifier — oddiy Dart klassi, unga unit-test yozish oson. Bog‘liqliklar bilan qiyinroq: ularni konstruktor orqali qo‘lda uzatishga to‘g‘ri keladi.

Riverpod. Kuchli tomoni — almashtirishlar (overrides). Repozitoriyni ishlab chiqarish kodiga tegmasdan soxta versiyaga almashtirish mumkin:

final container = ProviderContainer(
  overrides: [repositoryProvider.overrideWithValue(FakeRepository())],
);
addTearDown(container.dispose);

container.read(cartProvider.notifier).add(item);
expect(container.read(cartProvider), [item]);

BLoC. bloc_test paketi testni «kirishda shu hodisa — chiqishda shu holatlar ro‘yxati» shaklida yozish imkonini beradi. Bu murakkab ssenariylarda ayniqsa qulay: yuklanish, xato, qayta urinish.

Jamoaviy ish va ko‘lam

Katta loyihalarda asosiy muammo kutubxona tanlovi emas, balki turli uslublar. Har kim o‘zicha yozsa, istalgan yondashuv tartibsizlikka aylanadi.

  • BLoC tuzilmani majburlaydi: hodisa, ishlovchi, holat. Yangi dasturchi mantiqni qayerdan izlashni biladi.
  • Riverpod moslashuvchanroq, shuning uchun jamoa kelishib olishi kerak: provayderlar qayerda turadi, qanday nomlanadi, qachon Notifier, qachon FutureProvider ishlatiladi.
  • Katta loyihada Provider ko‘pincha o‘nlab maydonli, keng qayta chizishlarga sabab bo‘ladigan ulkan ChangeNotifier’larga olib keladi.

Loyiha hajmiga qarab tanlash

  1. Prototip, MVP, bir nechta ekran — Provider yoki Riverpod. G‘oyani tez tekshirish muhim.
  2. O‘rta hajmdagi mahsulot, kichik jamoa — Riverpod: BLoC’dan kamroq kod, yaxshi testlar va tayyor asinxronlik.
  3. Yirik ilova, bir nechta jamoa, qat’iy kod-revyu — BLoC yoki qat’iy uslub qo‘llanmasi bilan Riverpod. Ko‘pincha jamoa allaqachon yaxshi biladigan narsa hal qiladi.
  4. Mavjud loyiha — modaga ergashib hammasini qayta yozmang. Yangi modullarni yangi yondashuvda qiling, eskilarini bosqichma-bosqich ko‘chiring.

Ko‘p uchraydigan xatolar

  • Biznes-mantiq vidjetlar ichida. API so‘rovlari va validatsiya model, notifier yoki bloc’da turishi kerak.
  • Hammasi global. Bitta ekrandagi forma holatini butun ilova uchun global qilish shart emas.
  • Ortiqcha qayta chizishlar. Vidjet faqat kerakli maydonga javob berishi uchun selektorlardan foydalaning: context.select, ref.watch(provider.select(...)), BlocSelector.
  • Uchala yondashuvni aralashtirish — aniq sababsiz bitta loyihada.

Ko‘p beriladigan savollar

Texnik jihatdan ha, lekin bu qo‘llab-quvvatlashni qiyinlashtiradi: bog‘liqliklarni ulashning ikki usuli va ikki xil fikrlash modeli paydo bo‘ladi. Sabab bo‘lsa, masalan migratsiya, yangi kod qaysi yondashuvda yozilishini qayd etib qo‘ying.

Bunda yordam beramiz

O‘zingiz shug‘ullanmasdan natija olishni istasangiz — biz har kuni shu bilan shug‘ullanamiz.

Loyihani muhokama qilish

Yana o‘qing

G‘oya yoki vazifangiz bormi? Bizga aytib bering

Ish kuni davomida javob beramiz va yechim taklif qilamiz. Konsultatsiya bepul.