Flutter State Management
State management is a core concept in Flutter development.\n\nThis section will introduce Flutter's built-in state management approaches, including setState, Provider, and ChangeNotifier.\n\n* * *\n\n## What is State Management\n\nState management refers to the mechanism of managing data changes and UI updates in an application. When data changes, the UI needs to be updated accordingly; this is the problem that state management solves.\n\n| State Type | Description | Example |\n| --- | --- | --- |\n| Local State | State internal to a single Widget | Input field text, animation progress |\n| Shared State | State that multiple Widgets need to share | User login information, theme |\n| App State | State that the entire application needs to access | Shopping cart contents, user preferences |\n\n* * *\n\n## Local State - setState\n\nFor simple local states, using StatefulWidget and setState is sufficient.\n\n## Instance: Counter Example\n\nclass CounterWidget extends StatefulWidget {\n\nconst CounterWidget({super.key});\n\n@override\n\n State createState()=> _CounterWidgetState();\n\n}\n\nclass _CounterWidgetState extends State{\n\n// Local State\n\nint _count =0;\n\n// IncreaseCount\n\nvoid _increment(){\n\n setState((){\n\n _count++;\n\n});\n\n}\n\n// Decrement Count\n\nvoid _decrement(){\n\n setState((){\n\n _count--;\n\n});\n\n}\n\n@override\n\n Widget build(BuildContext context){\n\nreturn Column(\n\n mainAxisAlignment: MainAxisAlignment.center,\n\n children:[\n\n Text('Count: $_count', style:const TextStyle(fontSize:32)),\n\nconst SizedBox(height:20),\n\n Row(\n\n mainAxisAlignment: MainAxisAlignment.center,\n\n children:[\n\n ElevatedButton(onPressed: _decrement, child:const Text('-')),\n\nconst SizedBox(width:20),\n\n ElevatedButton(onPressed: _increment, child:const Text('+')),\n\n],\n\n),\n\n],\n\n);\n\n}\n\n}\n\n* * *\n\n## Provider State Management\n\nProvider is one of the state management solutions officially recommended by Flutter, suitable for managing state shared across components.\n\n### Installing Provider\n\nAdd the dependency in pubspec.yaml:\n\ndependencies: provider: ^6.0.0\n### ChangeNotifier Pattern\n\n## Instance: Provider + ChangeNotifier\n\n// 1. Define data model (extends ChangeNotifier)\n\nclass CounterModel extends ChangeNotifier {\n\nint _count =0;\n\nint get count => _count;\n\nvoid increment(){\n\n _count++;\n\n// Notify listeners that State has changed\n\n notifyListeners();\n\n}\n\nvoid decrement(){\n\n _count--;\n\n notifyListeners();\n\n}\n\n}\n\n// 2. Provide data at the app's top level\n\nvoid main(){\n\n runApp(\n\n// Provide CounterModel to child widgets\n\n ChangeNotifierProvider(\n\n create:(context)=> CounterModel(),\n\n child:const MyApp(),\n\n),\n\n);\n\n}\n\n// 3. Use data in the widget\n\nclass CounterDisplay extends StatelessWidget {\n\nconst CounterDisplay({super.key});\n\n@override\n\n Widget build(BuildContext context){\n\n// Read CounterModel\n\nfinal counter = context.watch();\n\nreturn Column(\n\n children:[\n\n Text('Count: ${counter.count}', style:const TextStyle(fontSize:32)),\n\n ElevatedButton(\n\n onPressed:()=> counter.increment(),\n\n child:const Text('Increase'),\n\n),\n\n],\n\n);\n\n}\n\n}\n\n### Multi-Provider Composition\n\n## Instance: Multi-Provider Usage\n\nvoid main(){\n\n runApp(\n\n MultiProvider(\n\n providers:[\n\n// User Info Provider\n\n ChangeNotifierProvider(create:(_)=> UserModel()),\n\n// Theme Provider\n\n ChangeNotifierProvider(create:(_)=> ThemeModel()),\n\n// Shopping Cart Provider\n\n ChangeNotifierProvider(create:(_)=> CartModel()),\n\n],\n\n child:const MyApp(),\n\n),\n\n);\n\n}\n\n// Use context.read When there is no need to listen for changes\n\nclass SomeWidget extends StatelessWidget {\n\nconst SomeWidget({super.key});\n\n@override\n\n Widget build(BuildContext context){\n\n// Read but do not listen\n\nfinal user = context.read();\n\nreturn ElevatedButton(\n\n onPressed:()=> user.logout(),\n\n child:const Text('Log out'),\n\n);\n\n}\n\n}\n\n* * *\n\n## Lifting State Up\n\nWhen multiple child components need to share state, the state can be lifted to the nearest common parent component.\n\n## Instance: Lifting State Up\n\n// Parent component manages State\n\nclass ParentWidget extends StatefulWidget {\n\nconst ParentWidget({super.key});\n\n@override\n\n State createState()=> _ParentWidgetState();\n\n}\n\nclass _ParentWidgetState extends State{\n\n// Shared State\n\nbool _isEnabled =false;\n\n// Callback method\n\nvoid _toggleEnabled(){\n\n setState((){\n\n _isEnabled =!_isEnabled;\n\n});\n\n}\n\n@override\n\n Widget build(BuildContext context){\n\nreturn Column(\n\n children:[\n\n// Child Widget A\n\n ChildWidgetA(\n\n isEnabled: _isEnabled,\n\n),\n\n// Child Widget B\n\n ChildWidgetB(\n\n isEnabled: _isEnabled,\n\n onToggle: _toggleEnabled,\n\n),\n\n],\n\n);\n\n}\n\n}\n\n// Child Widget AοΌOnly display State)\n\nclass ChildWidgetA extends StatelessWidget {\n\nfinal bool isEnabled;\n\nconst ChildWidgetA({super.key, required this.isEnabled});\n\n@override\n\n Widget build(BuildContext context){\n\nreturn Text('State: ${isEnabled ? "Enable" : "Disable"}');\n\n}\n\n}\n\n// Child Widget BοΌControl State)\n\nclass ChildWidgetB extends StatelessWidget {\n\nfinal bool isEnabled;\n\nfinal VoidCallback onToggle;\n\nconst ChildWidgetB({\n\nsuper.key,\n\n required this.isEnabled,\n\n required this.onToggle,\n\n});\n\n@override\n\n Widget build(BuildContext context){\n\nreturn ElevatedButton(\n\n onPressed: onToggle,\n\n child: Text(isEnabled ?'Disable':'Enable'),\n\n);\n\n}\n\n}\n\n> The choice of state management depends on the scale of the application: use setState for simple applications, Provider for medium-sized applications, and consider solutions like Riverpod, BLoC, or GetX for complex applications.
YouTip