6 तरीके Flutter Apps में State को Manage करने के (Code Examples के साथ)
Flutter में स्टेट को कैसे प्रबंधित करें
इस लेख में, हम छह लोकप्रिय तरीकों का पता लगाएंगे जो Flutter ऐप्स में स्टेट को प्रबंधित करने के हैं, जिसमें वास्तविक उदाहरण और सर्वोत्तम प्रथाएं शामिल हैं:
स्टेट प्रबंधन Flutter विकास में सबसे महत्वपूर्ण - और बहस का विषय है। यह निर्धारित करता है कि आपका ऐप डेटा में परिवर्तनों को कैसे संभालता है और UI को कुशलतापूर्वक अपडेट करता है। Flutter आपको स्टेट प्रबंधन के लिए कई रणनीतियां प्रदान करता है — सरल से लेकर अत्यधिक स्केलेबल तक।
Flutter में स्टेट प्रबंधन के लिए रणनीतियां हैं:
- 🧱
setState()
— बिल्ट-इन, सबसे सरल दृष्टिकोण - 🏗️ InheritedWidget — स्टेट प्रोपेगेशन के लिए Flutter का आधार
- 🪄 Provider — अधिकांश ऐप्स के लिए सिफारिश की गई समाधान
- 🔒 Riverpod — Provider का आधुनिक, कॉम्पाइल-सेफ़ विकास
- 📦 Bloc — स्केलेबल, एंटरप्राइज़-ग्रेड एप्लिकेशंस के लिए
- ⚡ GetX — हल्का, ऑल-इन-वन समाधान
1. setState()
का उपयोग — बेसिक्स
Flutter में स्टेट प्रबंधन का सबसे सरल तरीका है एक StatefulWidget
में बिल्ट-इन setState()
विधि का उपयोग करना।
यह दृष्टिकोण लोकल UI स्टेट के लिए आदर्श है — जहां स्टेट एक विड्जेट के लिए है और इसे ऐप के पूरे में साझा करने की आवश्यकता नहीं है।
उदाहरण: setState()
के साथ काउंटर ऐप
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: CounterScreen());
}
}
class CounterScreen extends StatefulWidget {
@override
_CounterScreenState createState() => _CounterScreenState();
}
class _CounterScreenState extends State<CounterScreen> {
int _count = 0;
void _increment() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('setState Counter')),
body: Center(
child: Text('Count: $_count', style: TextStyle(fontSize: 24)),
),
floatingActionButton: FloatingActionButton(
onPressed: _increment,
child: Icon(Icons.add),
),
);
}
}
लाभ
- बहुत सरल लागू करना
- स्थानीय या अस्थायी UI स्टेट के लिए अच्छा
- कोई बाहरी निर्भरताएं नहीं
हानियां
- बड़े ऐप्स के लिए स्केल नहीं करता
- विड्जेट्स के बीच स्टेट साझा करना कठिन है
- तर्क UI के साथ मिला हुआ है
इसका उपयोग करें जब:
- प्रोटोटाइपिंग या छोटे विड्जेट्स बनाना
- अलग-अलग UI स्टेट संभालना (उदाहरण के लिए, एक बटन टॉगल करना, एक मॉडल दिखाना)
2. InheritedWidget — Flutter का आधार
InheritedWidget
वह निम्न-स्तरीय तंत्र है जिसे Flutter विड्जेट ट्री के नीचे डेटा प्रोपेगेट करने के लिए उपयोग करता है। अधिकांश स्टेट प्रबंधन समाधान (Provider सहित) इसके ऊपर बनाए गए हैं।
InheritedWidget को समझना आपको यह समझने में मदद करता है कि Flutter का स्टेट प्रबंधन नीचे से कैसे काम करता है।
उदाहरण: InheritedWidget के साथ थीम मैनेजर
import 'package:flutter/material.dart';
// वह InheritedWidget जो थीम डेटा को रखता है
class AppTheme extends InheritedWidget {
final bool isDarkMode;
final Function toggleTheme;
const AppTheme({
Key? key,
required this.isDarkMode,
required this.toggleTheme,
required Widget child,
}) : super(key: key, child: child);
// विधि Access करने के लिए सबसे नजदीकी AppTheme को विड्जेट ट्री के ऊपर
static AppTheme? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<AppTheme>();
}
@override
bool updateShouldNotify(AppTheme oldWidget) {
return isDarkMode != oldWidget.isDarkMode;
}
}
// Stateful wrapper स्टेट परिवर्तनों को प्रबंधित करने के लिए
class ThemeManager extends StatefulWidget {
final Widget child;
const ThemeManager({Key? key, required this.child}) : super(key: key);
@override
_ThemeManagerState createState() => _ThemeManagerState();
}
class _ThemeManagerState extends State<ThemeManager> {
bool _isDarkMode = false;
void _toggleTheme() {
setState(() {
_isDarkMode = !_isDarkMode;
});
}
@override
Widget build(BuildContext context) {
return AppTheme(
isDarkMode: _isDarkMode,
toggleTheme: _toggleTheme,
child: widget.child,
);
}
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ThemeManager(
child: Builder(
builder: (context) {
final theme = AppTheme.of(context);
return MaterialApp(
theme: theme!.isDarkMode ? ThemeData.dark() : ThemeData.light(),
home: HomeScreen(),
);
},
),
);
}
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = AppTheme.of(context);
return Scaffold(
appBar: AppBar(title: Text('InheritedWidget Theme')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Current Theme: ${theme!.isDarkMode ? "Dark" : "Light"}',
style: TextStyle(fontSize: 20),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () => theme.toggleTheme(),
child: Text('Toggle Theme'),
),
],
),
),
);
}
}
लाभ
- Flutter में बिल्ट-इन — कोई बाहरी निर्भरताएं नहीं
- कुशल विड्जेट रीबिल्ड्स
- अन्य समाधानों को समझने का आधार
- प्रोपेगेशन तर्क पर सीधा नियंत्रण
हानियां
- बोइलरप्लेट कोड
- wrapper StatefulWidget की आवश्यकता
- गलतियों को करने का आसान
- नए उपयोगकर्ताओं के लिए अनुकूल नहीं
इसका उपयोग करें जब:
- यह सीखना कि Flutter का स्टेट प्रबंधन आंतरिक रूप से कैसे काम करता है
- कस्टम स्टेट प्रबंधन समाधान बनाना
- स्टेट प्रोपेगेशन पर बहुत विशिष्ट नियंत्रण की आवश्यकता है
3. Provider — Flutter की सिफारिश की गई समाधान
जब आपका ऐप का स्टेट कई विड्जेट्स के बीच साझा करने की आवश्यकता होती है, तो Provider बचाव के लिए आता है।
Provider Inversion of Control पर आधारित है — विड्जेट्स स्टेट को स्वामित्व नहीं करते, बल्कि एक प्रोवाइडर इसे अन्य लोगों के लिए उपभोग के लिए प्रकट करता है। Flutter के टीम द्वारा इसे मध्यम आकार के ऐप्स के लिए आधिकारिक रूप से सिफारिश की जाती है।
सेटअप
अपने pubspec.yaml
में यह जोड़ें:
dependencies:
provider: ^6.0.5
उदाहरण: Provider के साथ काउंटर ऐप
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (_) => CounterModel(),
child: MyApp(),
),
);
}
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: CounterScreen());
}
}
class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = context.watch<CounterModel>();
return Scaffold(
appBar: AppBar(title: Text('Provider Counter')),
body: Center(
child: Text('Count: ${counter.count}', style: TextStyle(fontSize: 24)),
),
floatingActionButton: FloatingActionButton(
onPressed: context.read<CounterModel>().increment,
child: Icon(Icons.add),
),
);
}
}
लाभ
- प्रतिक्रियाशील और कुशल अपडेट्स
- UI और तर्क के बीच साफ़ अलगाव
- अच्छी तरह से दस्तावेज़ीकृत और समुदाय द्वारा समर्थित
हानियां
setState()
की तुलना में थोड़ा अधिक बोइलरप्लेट- नेटेड प्रोवाइडर जटिल हो सकते हैं
इसका उपयोग करें जब:
- आपको कई विड्जेट्स के बीच साझा स्टेट की आवश्यकता है
- आप जटिलता के बिना एक प्रतिक्रियाशील पैटर्न चाहते हैं
- आपका ऐप प्रोटोटाइप आकार से बढ़ रहा है
4. Riverpod — प्रोवाइडर का आधुनिक विकास
Riverpod प्रोवाइडर का एक पूर्ण रूप से पुनः लिखित संस्करण है जो इसके BuildContext पर निर्भरता को हटा देता है और कंपाइल-टाइम सुरक्षा जोड़ता है। यह प्रोवाइडर की सीमाओं को हल करने के लिए डिज़ाइन किया गया है जबकि उसी दर्शन को बनाए रखता है।
सेटअप
अपने pubspec.yaml
में यह जोड़ें:
dependencies:
flutter_riverpod: ^2.4.0
उदाहरण: Riverpod के साथ उपयोगकर्ता प्रोफ़ाइल
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
// मॉडल
class UserProfile {
final String name;
final int age;
UserProfile({required this.name, required this.age});
UserProfile copyWith({String? name, int? age}) {
return UserProfile(
name: name ?? this.name,
age: age ?? this.age,
);
}
}
// स्टेट नोटिफायर
class ProfileNotifier extends StateNotifier<UserProfile> {
ProfileNotifier() : super(UserProfile(name: 'Guest', age: 0));
void updateName(String name) {
state = state.copyWith(name: name);
}
void updateAge(int age) {
state = state.copyWith(age: age);
}
}
// प्रोवाइडर
final profileProvider = StateNotifierProvider<ProfileNotifier, UserProfile>((ref) {
return ProfileNotifier();
});
// कंप्यूटेड प्रोवाइडर
final greetingProvider = Provider<String>((ref) {
final profile = ref.watch(profileProvider);
return 'नमस्ते, ${profile.name}! आप ${profile.age} वर्ष के हैं।';
});
void main() {
runApp(
ProviderScope(
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: ProfileScreen());
}
}
class ProfileScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final profile = ref.watch(profileProvider);
final greeting = ref.watch(greetingProvider);
return Scaffold(
appBar: AppBar(title: Text('Riverpod प्रोफ़ाइल')),
body: Padding(
padding: EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(greeting, style: TextStyle(fontSize: 20)),
SizedBox(height: 30),
TextField(
decoration: InputDecoration(labelText: 'नाम'),
onChanged: (value) {
ref.read(profileProvider.notifier).updateName(value);
},
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('उम्र: ${profile.age}', style: TextStyle(fontSize: 18)),
SizedBox(width: 20),
ElevatedButton(
onPressed: () {
ref.read(profileProvider.notifier).updateAge(profile.age + 1);
},
child: Text('+'),
),
SizedBox(width: 10),
ElevatedButton(
onPressed: () {
if (profile.age > 0) {
ref.read(profileProvider.notifier).updateAge(profile.age - 1);
}
},
child: Text('-'),
),
],
),
],
),
),
);
}
}
लाभ
- BuildContext निर्भरता नहीं — राज्य को कहीं भी एक्सेस करें
- कंपाइल-टाइम सुरक्षा — रनटाइम से पहले त्रुटियों का पता लगाएं
- बेहतर परीक्षण योग्यता
- शक्तिशाली राज्य संयोजन
- कोई मेमोरी लीक नहीं
हानियाँ
- पारंपरिक फ्लटर पैटर्न से अलग API
- प्रोवाइडर की तुलना में सीखने की कड़ी चढ़ाई
- छोटा समुदाय (लेकिन तेजी से बढ़ रहा है)
इसका उपयोग करें जब:
- एक नया फ्लटर प्रोजेक्ट शुरू कर रहे हों
- आप टाइप-सेफ्टी और कंपाइल-टाइम गारंटी चाहते हैं
- जटिल राज्य निर्भरताएं और संयोजन
- मध्यम से बड़े पैमाने के ऐप्स पर काम कर रहे हैं
5. BLoC (बिजनेस लॉजिक कंपोनेंट) — एंटरप्राइज़ ऐप्स के लिए
BLoC पैटर्न एक अधिक उन्नत आर्किटेक्चर है जो स्ट्रीम का उपयोग करके बिजनेस लॉजिक को UI से पूरी तरह से अलग करता है।
यह बड़े पैमाने या एंटरप्राइज़ एप्लिकेशन्स के लिए आदर्श है, जहां भविष्यवाणी योग्य और परीक्षण योग्य राज्य संक्रमण आवश्यक हैं।
सेटअप
अपने प्रोजेक्ट में इस निर्भरता को जोड़ें:
dependencies:
flutter_bloc: ^9.0.0
उदाहरण: BLoC के साथ काउंटर ऐप
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
// इवेंट्स
abstract class CounterEvent {}
class Increment extends CounterEvent {}
// Bloc
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0) {
on<Increment>((event, emit) => emit(state + 1));
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => CounterBloc(),
child: MaterialApp(home: CounterScreen()),
);
}
}
class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Bloc काउंटर')),
body: Center(
child: BlocBuilder<CounterBloc, int>(
builder: (context, count) {
return Text('काउंट: $count', style: TextStyle(fontSize: 24));
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read<CounterBloc>().add(Increment()),
child: Icon(Icons.add),
),
);
}
}
लाभ
- जटिल ऐप्स के लिए स्केलेबल और बनाए रखने योग्य
- परतों का स्पष्ट विभाजन
- यूनिट टेस्ट करने में आसान
हानियाँ
- अधिक बोइलरप्लेट
- सीखने की कड़ी चढ़ाई
इसका उपयोग करें जब:
- एंटरप्राइज़ या लंबे समय के प्रोजेक्ट्स बनाना
- आपको भविष्यवाणी योग्य और परीक्षण योग्य लॉजिक चाहिए
- कई डेवलपर्स अलग-अलग ऐप मॉड्यूल्स पर काम कर रहे हैं
6. GetX — ऑल-इन-वन लाइटवेट सॉल्यूशन
GetX एक मिनिमलिस्ट लेकिन शक्तिशाली स्टेट मैनेजमेंट सॉल्यूशन है जो रूटिंग, डिपेंडेंसी इंजेक्शन, और यूटिलिटीज भी शामिल करता है। यह सभी समाधानों में सबसे कम बोइलरप्लेट होने के लिए जाना जाता है।
सेटअप
अपने pubspec.yaml
में यह जोड़ें:
dependencies:
get: ^4.6.5
उदाहरण: GetX के साथ शॉपिंग लिस्ट
import 'package:flutter/material.dart';
import 'package:get/get.dart';
// कंट्रोलर
class ShoppingController extends GetxController {
// अवलोकन सूची
var items = <String>[].obs;
// अवलोकन काउंटर
var totalItems = 0.obs;
void addItem(String item) {
if (item.isNotEmpty) {
items.add(item);
totalItems.value = items.length;
}
}
void removeItem(int index) {
items.removeAt(index);
totalItems.value = items.length;
}
void clearAll() {
items.clear();
totalItems.value = 0;
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'GetX शॉपिंग लिस्ट',
home: ShoppingScreen(),
);
}
}
class ShoppingScreen extends StatelessWidget {
// कंट्रोलर इनिशियलाइज़ करें
final ShoppingController controller = Get.put(ShoppingController());
final TextEditingController textController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('GetX शॉपिंग लिस्ट'),
actions: [
Obx(() => Padding(
padding: EdgeInsets.all(16),
child: Center(
child: Text(
'आइटम्स: ${controller.totalItems}',
style: TextStyle(fontSize: 18),
),
),
)),
],
),
body: Column(
children: [
Padding(
padding: EdgeInsets.all(16),
child: Row(
children: [
Expanded(
child: TextField(
controller: textController,
decoration: InputDecoration(
hintText: 'आइटम का नाम दर्ज करें',
border: OutlineInputBorder(),
),
),
),
SizedBox(width: 10),
ElevatedButton(
onPressed: () {
controller.addItem(textController.text);
textController.clear();
},
child: Icon(Icons.add),
),
],
),
),
Expanded(
child: Obx(() {
if (controller.items.isEmpty) {
return Center(
child: Text('आपकी सूची में कोई आइटम नहीं है'),
);
}
return ListView.builder(
itemCount: controller.items.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(child: Text('${index + 1}')),
title: Text(controller.items[index]),
trailing: IconButton(
icon: Icon(Icons.delete, color: Colors.red),
onPressed: () => controller.removeItem(index),
),
);
},
);
}),
),
if (controller.items.isNotEmpty)
Padding(
padding: EdgeInsets.all(16),
child: ElevatedButton(
onPressed: () {
Get.defaultDialog(
title: 'सूची साफ करें',
middleText: 'क्या आप सभी आइटम्स को साफ करने की पुष्टि करते हैं?',
textConfirm: 'हाँ',
textCancel: 'नहीं',
onConfirm: () {
controller.clearAll();
Get.back();
},
);
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
minimumSize: Size(double.infinity, 50),
),
child: Text('सभी साफ करें'),
),
),
],
),
);
}
}
लाभ
- न्यूनतम बोइलरप्लेट — सबसे तेज़ विकास
- ऑल-इन-वन सॉल्यूशन (स्टेट, रूटिंग, DI, स्नैकबार, डायलॉग)
- BuildContext की आवश्यकता नहीं
- बहुत हल्का और तेज़
- सीखना आसान
हानियाँ
- प्रोवाइडर/BLoC की तुलना में कम “फ्लटर-जैसा”
- अगर सावधानी नहीं बरती तो कड़ी कपलिंग हो सकती है
- प्रोवाइडर से छोटा इकोसिस्टम
- कुछ डेवलपर्स इसे “बहुत जादूई” पाते हैं
इसका उपयोग करें जब:
- रैपिड प्रोटोटाइपिंग या MVP विकास
- छोटे से मध्यम ऐप्स
- आप न्यूनतम बोइलरप्लेट चाहते हैं
- टीम सरलता को कठोर आर्किटेक्चर पर पसंद करती है
उचित स्टेट मैनेजमेंट समाधान का चयन
समाधान | जटिलता | बॉइलरप्लेट | सीखने की कुरव | सर्वोत्तम उपयोग |
---|---|---|---|---|
🧱 setState() |
कम | न्यूनतम | आसान | सरल स्थानीय स्टेट, प्रोटोटाइप्स |
🏗️ InheritedWidget |
मध्यम | उच्च | मध्यम | Flutter इंटरनल्स सीखना, कस्टम समाधान |
🪄 Provider |
कम-मध्यम | कम | आसान | अधिकांश ऐप्स, साझा स्टेट |
🔒 Riverpod |
मध्यम | कम-मध्यम | मध्यम | आधुनिक ऐप्स, टाइप सुरक्षा |
📦 BLoC |
उच्च | उच्च | कठिन | एंटरप्राइज ऐप्स, जटिल बिजनेस लॉजिक |
⚡ GetX |
कम | न्यूनतम | आसान | तेज़ विकास, MVP |
त्वरित निर्णय गाइड:
ऐप जटिलता | सिफारिश की गई विधि | उदाहरण उपयोग |
---|---|---|
🪶 सरल | setState() या GetX |
टॉगल बटन, एनिमेशन, छोटे विगेट्स |
⚖️ मध्यम | Provider या Riverpod |
साझा थीम्स, यूजर सेटिंग्स, डेटा कैशिंग |
🏗️ जटिल | BLoC या Riverpod |
ई-कॉमर्स, चैट ऐप्स, वित्तीय डैशबोर्ड |
अंतिम विचार
Flutter में स्टेट मैनेजमेंट के लिए एक ही आकार सभी के लिए कोई उपाय नहीं है।
यहाँ एक व्यावहारिक दृष्टिकोण है:
setState()
के साथ छोटे पैमाने से शुरू करें सरल विगेट्स और प्रोटोटाइप्स के लिए- मूलभूत सिद्धांतों को सीखें InheritedWidget के साथ Flutter के आंतरिक कार्यप्रणाली को समझने के लिए
- Provider पर आगे बढ़ें जब आपका ऐप बढ़ता है और साझा स्टेट की आवश्यकता होती है
- Riverpod के बारे में विचार करें नए प्रोजेक्ट्स के लिए जहां टाइप सुरक्षा और आधुनिक पैटर्न महत्वपूर्ण हैं
- BLoC को अपनाएं बड़े एंटरप्राइज एप्लिकेशन्स के लिए जटिल बिजनेस लॉजिक के साथ
- GetX का प्रयास करें जब तेज़ विकास और न्यूनतम बॉइलरप्लेट प्राथमिकता हैं
मुख्य सीख:
✅ ओवर-इंजीनियरिंग न करें — setState()
का उपयोग करें जब तक आप अधिक की आवश्यकता नहीं महसूस करते
✅ Provider और Riverpod अधिकांश एप्लिकेशन्स के लिए उत्कृष्ट विकल्प हैं
✅ BLoC बड़े टीम्स और जटिल ऐप्स में चमकता है
✅ GetX गति के लिए अच्छा है, लेकिन कूपलिंग के बारे में सावधान रहें
✅ InheritedWidget को समझना आपको किसी भी समाधान को मास्टर करने में मदद करता है
मुख्य बात यह है कि सरलता, स्केलेबिलिटी, और मेन्टेनबिलिटी के बीच संतुलन बनाए रखें — और अपने विशिष्ट आवश्यकताओं, टीम की विशेषज्ञता, और प्रोजेक्ट आवश्यकताओं के लिए सही उपकरण का चयन करें।
Flutter स्टेट मैनेजमेंट लाइब्रेरी लिंक्स
- Flutter आधिकारिक दस्तावेज़ स्टेट मैनेजमेंट पर
- Provider पैकेज
- Riverpod दस्तावेज़
- BLoC लाइब्रेरी
- GetX दस्तावेज़