স্কিপ করে মূল কন্টেন্ট এ যাও

StateProvider

StateProvider হল একটি প্রভাইডার যেটি তার অবস্থা পরিবর্তন করার একটি উপায় প্রকাশ করে। এটি StateNotifierProvider-এর একটি সরলীকরণ, খুব সাধারণ ব্যবহারের ক্ষেত্রে একটি StateNotifier ক্লাস লিখতে না দেওয়ার জন্য ডিজাইন করা হয়েছে।

StateProvider এর পরিবর্তনের অনুমতি দেওয়ার জন্য প্রাথমিকভাবে বিদ্যমান ইউজার ইন্টারফেস দ্বারা সহজ ভেরিয়েবল।

একটি StateProvider-এর স্টেট সাধারণতঃ

  • একটি enum, যেমন একটি ফিল্টার প্রকার
  • একটি স্ট্রিং, সাধারণত একটি পাঠ্য ক্ষেত্রের কাঁচা বিষয়বস্তু
  • একটি বুলিয়ান, চেকবক্সের জন্য
  • একটি সংখ্যা, পেজিনেশন বা বয়স ফর্ম ক্ষেত্রের জন্য

আপনার 'StateProvider' ব্যবহার করা উচিত নয় যদি:

  • আপনার স্ট্যাট বৈধতা যুক্তি প্রয়োজন
  • আপনার স্ট্যাট একটি জটিল বস্তু (যেমন একটি কাস্টম ক্লাস, একটি list/map, ...)
  • আপনার অবস্থা পরিবর্তন করার লজিক একটি সাধারণ count++ এর চেয়ে আরও উন্নত।

আরও উন্নত ক্ষেত্রে, পরিবর্তে StateNotifierProvider ব্যবহার করার কথা বিবেচনা করুন এবং একটি StateNotifier ক্লাস তৈরি করুন। যদিও প্রাথমিক বয়লারপ্লেটটি একটু বড় হবে, একটি কাস্টম StateNotifier ক্লাস থাকা আপনার প্রকল্পের দীর্ঘমেয়াদী রক্ষণাবেক্ষণের জন্য গুরুত্বপূর্ণ - কারণ এটি আপনার ষ্টেটের বিজনেস লজিককে একক জায়গায় কেন্দ্রীভূত করে।

ব্যবহারের উদাহরণ: ড্রপডাউন ব্যবহার করে ফিল্টারের ধরন পরিবর্তন করা

ড্রপডাউন/টেক্সট ফিল্ড/চেকবক্সের মতো সাধারণ ফর্ম উপাদানগুলির অবস্থা পরিচালনা করা হল StateProvider-এর একটি বাস্তব-বিশ্ব ব্যবহার-কেস। বিশেষ করে, আমরা দেখব কীভাবে একটি ড্রপডাউন বাস্তবায়ন করতে StateProvider ব্যবহার করতে হয় যা পণ্যের তালিকা কীভাবে সাজানো হয় তা পরিবর্তন করতে দেয়।

সরলতার খাতিরে, আমরা যে পণ্যগুলি প্রাপ্ত করব তার তালিকা অ্যাপ্লিকেশনটিতে সরাসরি তৈরি করা হবে এবং নিম্নরূপ হবে:


class Product {
Product({required this.name, required this.price});

final String name;
final double price;
}

final _products = [
Product(name: 'iPhone', price: 999),
Product(name: 'cookie', price: 2),
Product(name: 'ps5', price: 500),
];

final productsProvider = Provider<List<Product>>((ref) {
return _products;
});

একটি বাস্তব-বিশ্বের অ্যাপ্লিকেশনে, এই তালিকাটি সাধারণত একটি নেটওয়ার্ক রিকুয়েস্ট করে FutureProvider ব্যবহার করে প্রাপ্ত করা হবে।

ইউজার ইন্টারফেস তারপর করে পণ্যের তালিকা দেখাতে পারেঃ


Widget build(BuildContext context, WidgetRef ref) {
final products = ref.watch(productsProvider);
return Scaffold(
body: ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
final product = products[index];
return ListTile(
title: Text(product.name),
subtitle: Text('${product.price} \$'),
);
},
),
);
}

এখন যেহেতু আমরা বেস দিয়ে শেষ করেছি, আমরা একটি ড্রপডাউন যোগ করতে পারি, যা মূল্য বা নাম অনুসারে আমাদের পণ্যগুলিকে ফিল্টার করার অনুমতি দেবে৷ এর জন্য, আমরা DropDownButton ব্যবহার করব।


//এ কটি enum যা ফিল্টার টাইপ রিপ্রেসেন্ট করে
enum ProductSortType {
name,
price,
}

Widget build(BuildContext context, WidgetRef ref) {
final products = ref.watch(productsProvider);
return Scaffold(
appBar: AppBar(
title: const Text('Products'),
actions: [
DropdownButton<ProductSortType>(
value: ProductSortType.price,
onChanged: (value) {},
items: const [
DropdownMenuItem(
value: ProductSortType.name,
child: Icon(Icons.sort_by_alpha),
),
DropdownMenuItem(
value: ProductSortType.price,
child: Icon(Icons.sort),
),
],
),
],
),
body: ListView.builder(
// ... /* SKIP */
itemBuilder: (c, i) => Container(), /* SKIP END */
),
);
}

এখন আমাদের একটি ড্রপডাউন আছে, আসুন একটি StateProvider তৈরি করি এবং আমাদের প্রদানকারীর সাথে ড্রপডাউনের অবস্থা সিঙ্ক্রোনাইজ করুন।

প্রথমে, আসুন StateProvider তৈরি করিঃ


final productSortTypeProvider = StateProvider<ProductSortType>(
// আমরা ডিফল্ট সর্ট টাইপ রিটার্ন দিই, এখানে নাম।
(ref) => ProductSortType.name,
);

তারপর, আমরা এই প্রভাইডারকে আমাদের ড্রপডাউনের সাথে সংযুক্ত করতে পারিঃ

DropdownButton<ProductSortType>(
// যখন সর্ট টাইপ পরিবর্তিত হয়, এটি প্রদর্শিত আইকন আপডেট করতে ড্রপডাউনটি পুনর্নির্মাণ করবে।
value: ref.watch(productSortTypeProvider),
// যখন ব্যবহারকারী ড্রপডাউনের সাথে ইন্টারঅ্যাক্ট করে, তখন আমরা প্রভাইডারের স্টেট আপডেট করি।
onChanged: (value) =>
ref.read(productSortTypeProvider.notifier).state = value!,
items: [
// ...
],
),

এই সঙ্গে, আমরা এখন সাজানোর ধরন পরিবর্তন করতে সক্ষম হওয়া উচিত. যদিও পণ্যের তালিকায় এর কোনো প্রভাব পড়েনি! এটি এখন চূড়ান্ত অংশের জন্য সময়: পণ্যের তালিকা বাছাই করতে আমাদের productsProvider আপডেট করা হচ্ছে।

এটি বাস্তবায়নের একটি মূল উপাদান হল ref.watch ব্যবহার করা আমাদের productsProvider সাজানোর ধরন পায় এবং এর তালিকা পুনরায় গণনা করে পণ্য যখনই সাজানোর ধরন পরিবর্তিত হয়।

বাস্তবায়ন হবে এভাবেঃ


final productsProvider = Provider<List<Product>>((ref) {
final sortType = ref.watch(productSortTypeProvider);
switch (sortType) {
case ProductSortType.name:
return _products.sorted((a, b) => a.name.compareTo(b.name));
case ProductSortType.price:
return _products.sorted((a, b) => a.price.compareTo(b.price));
}
});

এখানেই শেষ! এই পরিবর্তনটি ব্যবহারকারী ইন্টারফেসের জন্য যথেষ্ট যাতে পণ্যের তালিকাটি সাজানোর ধরণ পরিবর্তন হলে স্বয়ংক্রিয়ভাবে পুনরায় রেন্ডার করা যায়।

এখানে ডার্টপ্যাডের সম্পূর্ণ উদাহরণ রয়েছেঃ

প্রভাইডারকে দুবার রিড না করে আগের মানের উপর ভিত্তি করে কীভাবে স্ট্যাট আপডেট করবেন

কখনও কখনও, আপনি পূর্ববর্তী মানের উপর ভিত্তি করে একটি StateProvider-এর অবস্থা আপডেট করতে চান। স্বাভাবিকভাবেই, আপনি এভাবে লিখতে পারেনঃ


final counterProvider = StateProvider<int>((ref) => 0);

class HomeView extends ConsumerWidget {
const HomeView({super.key});


Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
// আমরা পূর্ববর্তী মান থেকে স্ট্যাট আপডেট করছি, আমরা দুইবার প্রভাইডার রিড করে ফেলছি!
ref.read(counterProvider.notifier).state =
ref.read(counterProvider.notifier).state + 1;
},
),
);
}
}

যদিও এই স্নিপেটের সাথে বিশেষভাবে ভুল কিছু নেই, সিনট্যাক্সটি কিছুটা অসুবিধাজনক।

সিনট্যাক্স একটু ভালো করতে, আমরা update ফাংশন ব্যবহার করতে পারি। এই ফাংশনটি একটি কলব্যাক নেবে যা বর্তমান অবস্থা গ্রহণ করবে এবং নতুন অবস্থায় ফিরে আসবে বলে আশা করা যায়।

আমরা আমাদের পূর্ববর্তী কোড রিফ্যাক্টর করতে এটি ব্যবহার করতে পারিঃ


final counterProvider = StateProvider<int>((ref) => 0);

class HomeView extends ConsumerWidget {
const HomeView({super.key});


Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
ref.read(counterProvider.notifier).update((state) => state + 1);
},
),
);
}
}

এই পরিবর্তনটি একই প্রভাব অর্জন করে যখন সিনট্যাক্সটিকে কিছুটা ভাল করে তোলে।