Last active
December 13, 2024 02:07
-
-
Save temoki/0e9acedbfa2b6ebe424f7e856dc2f5f3 to your computer and use it in GitHub Desktop.
Open with DartPad ๐ https://dartpad.dev/?id=0e9acedbfa2b6ebe424f7e856dc2f5f3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//================================================================================ | |
// Flutter State Management Guide (1) | |
// | |
// f(State) = UI | |
// | |
// It means the UI is a function of the current state. | |
// When the state changes, the UI automatically updates to reflect it. | |
//================================================================================ | |
import 'package:flutter/material.dart'; | |
import 'package:provider/provider.dart' as provider; | |
import 'package:hooks_riverpod/hooks_riverpod.dart' as riverpod; | |
void main() => runApp(const App()); | |
final class App extends StatelessWidget { | |
const App({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return riverpod.ProviderScope( | |
child: MediaQuery( | |
data: MediaQuery.of(context).copyWith( | |
textScaler: TextScaler.linear(2.0), | |
), | |
child: MaterialApp( | |
title: 'Flutter State Management Guide', | |
debugShowCheckedModeBanner: false, | |
theme: ThemeData(colorSchemeSeed: Colors.blue), | |
home: Scaffold( | |
appBar: AppBar(title: Text('Flutter State Management')), | |
body: ListView( | |
children: [ | |
_ListItem( | |
1, | |
'Stateless', | |
(_) => Case1Page(), | |
), | |
_ListItem( | |
2, | |
'Stateful / Single Widget', | |
(_) => Case2Page(), | |
), | |
_ListItem( | |
3, | |
'Stateful / Multiple Widgets / State Lift Up', | |
(_) => Case3Page(), | |
), | |
_ListItem( | |
4, | |
'Stateful / Multiple Widgets / ChangeNotifier', | |
(_) => Case4Page(), | |
), | |
_ListItem( | |
5, | |
'Stateful / Multiple Widgets / ChangeNotifier + InheritedWidget', | |
(_) => Case5Page(), | |
), | |
_ListItem( | |
6, | |
'Stateful / Multiple Widgets / ChangeNotifier + Provider', | |
(_) => Case6Page(), | |
), | |
_ListItem( | |
7, | |
'Stateful / Multiple Widgets / ChangeNotifier + Riverpod', | |
(_) => Case7Page(), | |
), | |
_ListItem( | |
8, | |
'Stateful / Multiple Widgets / Notifier + Riverpod', | |
(_) => Case8Page(), | |
), | |
], | |
), | |
), | |
), | |
), | |
); | |
} | |
} | |
final class _ListItem extends StatelessWidget { | |
_ListItem(this.no, this.description, this.builder); | |
final int no; | |
final String description; | |
final WidgetBuilder builder; | |
@override | |
Widget build(BuildContext context) { | |
final title = 'Case $no'; | |
return ListTile( | |
title: Text(title), | |
subtitle: Text(description), | |
onTap: () => Navigator.of(context).push( | |
MaterialPageRoute( | |
builder: (c) => Scaffold( | |
appBar: AppBar( | |
title: Text(title), | |
bottom: _Description(description), | |
), | |
body: builder(c), | |
), | |
), | |
), | |
); | |
} | |
} | |
final class _Description extends StatelessWidget | |
implements PreferredSizeWidget { | |
_Description(this.description); | |
final String description; | |
@override | |
Widget build(BuildContext context) { | |
return SizedBox( | |
height: 40, | |
child: Text(description, style: TextStyle(fontSize: 10)), | |
); | |
} | |
@override | |
Size get preferredSize => Size.fromHeight(40); | |
} | |
//================================================================================ | |
// CASE 1 : Stateless | |
// | |
// * `StatelessWidget` ใฏ็ถๆ ใใใใชใ Widget | |
// | |
// โ-----------------โ | |
// โ โ | |
// โ StatelessWidget โ | |
// โ โ | |
// โ-----------------โ | |
//================================================================================ | |
final class Case1Page extends StatelessWidget { | |
const Case1Page({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
debugPrint('Case1Page build'); | |
return Center( | |
child: Text("I'm static"), | |
); | |
} | |
} | |
//================================================================================ | |
// CASE 2 : Stateful / Single Widget | |
// | |
// * `StatefulWidget` ใฏ็ถๆ ใใใค Widget | |
// * `State` ใฏใฉในใฎใใฃใผใซใใ็ถๆ ใจใชใ | |
// * `initState()` ใกใฝใใใใชใผใใผใฉใคใใใใใจใง็ถๆ ใฎๅๆๅใใงใใ๏ผๅๅใใซใๆใฎใฟๅฎ่กใใใ๏ผ | |
// * `setState()` ใกใฝใใใฎไธญใงใใฃใผใซใใๆดๆฐใใใใจใงใชใใซใใไฟใใ | |
// * ใใฎ Widget ๅ ใฎใฟใงๅ็ งใใใ็ถๆ ใชใฎใง local state ใ ephemeral state ใจๅผใฐใใ | |
// | |
// โ-----------------โ | |
// โ โ | |
// โ StatefulWidget โ โ-------โ | |
// โ โผ--------โผ State โ | |
// โ-----------------โ โ-------โ | |
//================================================================================ | |
final class Case2Page extends StatefulWidget { | |
const Case2Page({super.key}); | |
State<Case2Page> createState() => Case2State(); | |
} | |
final class Case2State extends State<Case2Page> { | |
Case2State(); | |
int _count = -1; | |
@override | |
void initState() { | |
_count = 0; | |
super.initState(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
debugPrint('Case2Page build : $_count'); | |
return Center( | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
Text("Count = $_count"), | |
const SizedBox(height: 8), | |
FilledButton( | |
onPressed: () { | |
setState(() => _count++); | |
}, | |
child: const Text('+'), | |
), | |
], | |
), | |
); | |
} | |
} | |
//================================================================================ | |
// CASE 3 : Stateful / Multiple Widgets / State Lift Up | |
// | |
// * ่คๆฐใฎ Widget ใงๅ ฑ้ใฎ็ถๆ ใใใๅ ดๅใใใใใฎๅ ฑ้ใฎ็ฅๅ ใฎ Widget ใพใง็ถๆ ใ็งปๅใใใ | |
// * ็ฅๅ ใฎ Widget ใใใ็ถๆ ใๅฟ ่ฆใจใใๅญๅญซใฎ Widge ใพใง็ถๆ ใไผๆฌใใใ๏ผใใฑใใชใฌใผ๏ผ | |
// | |
// โ---------------โ | |
// โStatelessWidgetโ | |
// โ (A) โ | |
// โ-------โฌ-------โ | |
// โ | |
// โ------------โด-------------โ | |
// โ-------โด-------โ โ-------โด-------โ | |
// โStatefulWidget โ โ-----โ โStatelessWidgetโ | |
// โ (B) โผ-โคStateโ โ (C) โ | |
// โ---------------โ โ-----โ โ---------------โ | |
// | |
// โ State Lift Up! โ | |
// | |
// โ---------------โ | |
// โStatefulWidget โ โ-----โ | |
// โ (A) โ-โคStateโ | |
// โ-------โฌ-------โ โ-----โ | |
// โ | |
// โ------------โด-------------โ | |
// โ-------โด-------โ โ-------โด-------โ | |
// โStatelessWidgetโ โStatelessWidgetโ | |
// โ (B) โ โ (C) โ | |
// โ---------------โ โ---------------โ | |
// | |
// Widget (has state) | |
// โ Child Widget (use state) | |
// โ Button (update state) | |
//================================================================================ | |
final class Case3Page extends StatefulWidget { | |
const Case3Page({super.key}); | |
State<Case3Page> createState() => Case3State(); | |
} | |
final class Case3State extends State<Case3Page> { | |
Case3State(); | |
int _count = 0; | |
@override | |
Widget build(BuildContext context) { | |
debugPrint('Case3State build'); | |
return Center( | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
CountWidget(count: _count), | |
CountDoubleWidget(count: _count), | |
EvenOddWidget(count: _count), | |
const SizedBox(height: 8), | |
FilledButton( | |
onPressed: () => setState(() => _count++), | |
child: const Text('+'), | |
), | |
], | |
), | |
); | |
} | |
} | |
final class CountWidget extends StatelessWidget { | |
const CountWidget({super.key, required this.count}); | |
final int count; | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
color: Colors.cyan, | |
padding: EdgeInsets.all(8), | |
child: Text('CountWidget\nCount = $count'), | |
); | |
} | |
} | |
final class CountDoubleWidget extends StatelessWidget { | |
const CountDoubleWidget({super.key, required this.count}); | |
final int count; | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
color: Colors.lime, | |
padding: EdgeInsets.all(8), | |
child: Text('CountDoubleWidget\nCount x 2 = ${count * 2}'), | |
); | |
} | |
} | |
final class EvenOddWidget extends StatelessWidget { | |
const EvenOddWidget({super.key, required this.count}); | |
final int count; | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
color: Colors.yellow, | |
padding: EdgeInsets.all(8), | |
child: Text('EvenOddWidget\nCount is ${count % 2 == 0 ? 'even' : 'odd'}'), | |
); | |
} | |
} | |
//================================================================================ | |
// CASE 4 : Stateful / Multiple Widgets / ChangeNotifier | |
// | |
// * ็ถๆ ใจใใฎ็ถๆ ๆดๆฐใญใธใใฏใๅๅฑ ใใใใใใฎใ `ChangeNotifier` | |
// * https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html | |
// * `notifyListeners()` ใซใใ็ถๆ ใฎๆดๆฐใ้็ฅใใใใจใใงใใ | |
// * `ListenableBuilder()` ใซ `ChangeNotifier` ใๆๅฎใใใจใใใฎ้ ไธใฎ Widget ใฏ | |
// `ChangeNotifier` ใฎ็ถๆ ใๆดๆฐใใใใใณใซใชใใซใใใใ | |
// | |
// โ-----------------โ | |
// โ โ โ--------------โ | |
// โ StatelessWidget โ โChangeNotifierโ | |
// โ โผ--โผ (State) โ | |
// โ--------โฌ--------โ โ--------------โ | |
// โ | |
// โ--------โด--------โ | |
// โListenableBuilderโ | |
// โ--------โฌ--------โ | |
// โ | |
// โ----------โด-----------โ | |
// โWidget that uses stateโ | |
// โ----------------------โ | |
// | |
// Widget (has ChangeNotifier) | |
// โ ListenableBuilder (Rebuild on ChangeNotifier change) | |
// โ Child Widget (use state via ChangeNotifier) | |
// โ Button (update state via ChangeNotifier) | |
//================================================================================ | |
final class CounterChangeNotifier with ChangeNotifier { | |
int _count = 0; | |
int get count => _count; | |
void increment() { | |
_count++; | |
notifyListeners(); | |
} | |
} | |
final class Case4Page extends StatelessWidget { | |
Case4Page(); | |
final _counter = CounterChangeNotifier(); | |
@override | |
Widget build(BuildContext context) { | |
debugPrint('Case4Page build'); | |
return ListenableBuilder( | |
listenable: _counter, | |
builder: (_, __) { | |
debugPrint('Case4Page/ListenableBuilder child build'); | |
return Center( | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
CountWidget(count: _counter.count), | |
CountDoubleWidget(count: _counter.count), | |
EvenOddWidget(count: _counter.count), | |
const SizedBox(height: 8), | |
FilledButton( | |
onPressed: () => _counter.increment(), | |
child: const Text('+'), | |
), | |
], | |
), | |
); | |
}, | |
); | |
} | |
} | |
//================================================================================ | |
// CASE 5 : Stateful / Multiple Widgets / ChangeNotifier + InheritedWidget | |
// | |
// * `InheritedWidget` ใฎๅญๅญซใฎ Widget ใฏ `{InheritedWidget}.of(context)` ใซใฆ | |
// ็ฅๅ ใซใใๆๅใฎ `InheritedWidget` ใๅๅพใใใใจใใงใใ | |
// * https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html | |
// * `InheritedWidget` ใฎๅฎ่ฃ ใ้ขๅใใใใใซใใ | |
// | |
// โ-----------------โ | |
// โ โ โ--------------โ | |
// โ InheritedWidget โ โChangeNotifierโ | |
// โ---โบโ โผ--โผ (State) โ | |
// โ โ--------โฌ--------โ โ--------------โ | |
// โ โ | |
// โ โ--------โด--------โ | |
// โ โ (Child) โ | |
// โ โ--------โฌ--------โ | |
// โ โ | |
// โ ... | |
// โ โ | |
// โof โ--------โด--------โ | |
// โ----โผ (Descendant) โ | |
// โ--------โฌ--------โ | |
// โ | |
// โ--------โด--------โ | |
// โListenableBuilderโ | |
// โ--------โฌ--------โ | |
// โ | |
// โ----------โด-----------โ | |
// โWidget that uses stateโ | |
// โ----------------------โ | |
// | |
// InheritedWidget (has ChangeNotifier) | |
// โ Child Widget | |
// โ ... | |
// โ ListenableBuilder (Rebuild on ChangeNotifier change) | |
// โ Descendant Widget 1 (use state via ChangeNotifier) | |
// โ Button (update state via ChangeNotifier) | |
//================================================================================ | |
class CounterInheritedWidget extends InheritedWidget { | |
const CounterInheritedWidget({ | |
super.key, | |
required this.counter, | |
required super.child, | |
}); | |
final CounterChangeNotifier counter; | |
@override | |
bool updateShouldNotify(CounterInheritedWidget oldWidget) => false; | |
static CounterInheritedWidget of(BuildContext context) { | |
final widget = context | |
.getElementForInheritedWidgetOfExactType<CounterInheritedWidget>() | |
?.widget as CounterInheritedWidget?; | |
if (widget != null) { | |
return widget; | |
} | |
throw Exception('No Case3CounterInheritedWidget found in context'); | |
} | |
} | |
final class Case5Page extends StatelessWidget { | |
Case5Page(); | |
@override | |
Widget build(BuildContext context) { | |
debugPrint('Case5Page build'); | |
return CounterInheritedWidget( | |
counter: CounterChangeNotifier(), | |
child: Case5ChildWidget(), | |
); | |
} | |
} | |
final class Case5ChildWidget extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
debugPrint('Case5ChildWidget build'); | |
final counter = CounterInheritedWidget.of(context).counter; | |
return ListenableBuilder( | |
listenable: counter, | |
builder: (_, __) { | |
debugPrint('Case5ChildWidget/ListenableBuilder child build'); | |
return Center( | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
CountWidget(count: counter.count), | |
CountDoubleWidget(count: counter.count), | |
EvenOddWidget(count: counter.count), | |
const SizedBox(height: 8), | |
FilledButton( | |
onPressed: () => counter.increment(), | |
child: const Text('+'), | |
), | |
], | |
), | |
); | |
}, | |
); | |
} | |
} | |
//================================================================================ | |
// CASE 6 : Stateful / Multiple Widgets / ChangeNotifier + Provider | |
// | |
// * `InheritedWidget` ใจๅ็ญใฎใใจใ็ฐกๅใซใใฆใใใใฎใ 3rd Party ใฎ Provider ใใใฑใผใธ | |
// * https://pub.dev/packages/provider | |
// * Flutter ใฎๅ ฌๅผใใญใฅใกใณใใซใใใฆใ็ถๆ ็ฎก็ๆๆณใฎ๏ผใคใจใใฆ็ดนไปใใใฆใใ | |
// * https://docs.flutter.dev/data-and-backend/state-mgmt/simple | |
// | |
// โ-----------------โ โ--------------โ | |
// โ ChangeNotifier โ โChangeNotifierโ | |
// โ---โบโ Provider โผ--โผ (State) โ | |
// โ โ--------โฌ--------โ โ--------------โ | |
// โ โ | |
// โ โ--------โด--------โ | |
// โ โ (Child) โ | |
// โ โ--------โฌ--------โ | |
// โ โ | |
// โ ... | |
// โ โ | |
// โof โ--------โด--------โ | |
// โ----โผ (Descendant) โ | |
// โ--------โฌ--------โ | |
// โ | |
// โ----------โด-----------โ | |
// โWidget that uses stateโ | |
// โ----------------------โ | |
// | |
// Widget | |
// โ ChangeNotifierProvider (has ChangeNotifier) | |
// โ ... | |
// โ Consumer<ChangeNotifier> (Rebuild on ChangeNotifier change) | |
// โ Descendant Widget 1 (use state via ChangeNotifier) | |
// โ Button (update state via ChangeNotifier) | |
//================================================================================ | |
final class Case6Page extends StatelessWidget { | |
Case6Page(); | |
@override | |
Widget build(BuildContext context) { | |
debugPrint('Case6Page build'); | |
return provider.ChangeNotifierProvider( | |
create: (context) => CounterChangeNotifier(), | |
child: Case6ChildWidget(), | |
); | |
} | |
} | |
final class Case6ChildWidget extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
debugPrint('Case6ChildWidget build'); | |
return provider.Consumer<CounterChangeNotifier>( | |
builder: (_, counter, __) { | |
debugPrint('Case5ChildWidget/Consumer child build'); | |
return Center( | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
CountWidget(count: counter.count), | |
CountDoubleWidget(count: counter.count), | |
EvenOddWidget(count: counter.count), | |
const SizedBox(height: 8), | |
FilledButton( | |
onPressed: () => counter.increment(), | |
child: const Text('+'), | |
), | |
], | |
), | |
); | |
}, | |
); | |
} | |
} | |
//================================================================================ | |
// CASE 7 : Stateful / Multiple Widgets / ChangeNotifier + Riverpod | |
// | |
// * Provider ใใใฑใผใธใฎไฝ่ ๏ผRemiใใ๏ผใใProvider ใฎๅ้ก็นใ่งฃๆถใในใ้็บใใใฎใ Riverpod | |
// * https://riverpod.dev | |
// * ๅ็งฐใฏ Provider ใฎใขใใฐใฉใ | |
// * Provider ใใใฑใผใธใงใฏๅใใฏใฉในใฎใชใใธใงใฏใใ่คๆฐๆไพใงใใชใ | |
// * ใใกใใ Flutter ใฎๅ ฌๅผใใญใฅใกใณใใซใใใฆใ็ถๆ ็ฎก็ๆๆณใฎ๏ผใคใจใใฆ็ดนไปใใใฆใใ | |
// * https://docs.flutter.dev/data-and-backend/state-mgmt/simple | |
// * Riverpod ใฎ Provider๏ผๅใๅๅใงใใใใใ๏ผใฏใๆไพใใใใชใใธใงใฏใใฎ็ๆๆนๆณใจ | |
// ใใฎใชใใธใงใฏใใซใขใฏใปในใใใใใฎใญใผใๆ ใ | |
// * Riverpod ใฎ Provider ใซใขใฏใปในใงใใใฎใฏ `ConsumerWidget` ใ็ถๆฟใใ Widget ใฎใฟใงใ | |
// ใใซใใกใฝใใใซ่ฟฝๅ ใใใ `WidgetRef` ใไปใใฆใขใฏใปในใใ | |
// * `WidgetRef` ใฎ `watch` ใไฝฟใใฐใใใฎใชใใธใงใฏใใฎ็ถๆ ใๅคใใฃใๆใซใชใใซใใ่ตฐใ | |
// | |
// ProviderScope (has ChangeNotifier) | |
// โ ... | |
// โ ConsumerWidget (watch ChangeNotifier via Provider, Rebuild on ChangeNotifier change) | |
// โ Descendant Widget 1 (use state via ChangeNotifier) | |
// โ Button (update state via ChangeNotifier) | |
//================================================================================ | |
final counterChangeNotifierProvider = | |
riverpod.ChangeNotifierProvider<CounterChangeNotifier>((ref) { | |
return CounterChangeNotifier(); | |
}); | |
final class Case7Page extends riverpod.ConsumerWidget { | |
@override | |
Widget build(BuildContext context, riverpod.WidgetRef ref) { | |
debugPrint('Case7Page build'); | |
final counter = ref.watch(counterChangeNotifierProvider); | |
return Center( | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
CountWidget(count: counter.count), | |
CountDoubleWidget(count: counter.count), | |
EvenOddWidget(count: counter.count), | |
const SizedBox(height: 8), | |
FilledButton( | |
onPressed: () => counter.increment(), | |
child: const Text('+'), | |
), | |
], | |
), | |
); | |
} | |
} | |
//================================================================================ | |
// CASE 8 : Stateful / Multiple Widgets / Notifier + Riverpod | |
// | |
// * Riverpod ใ `ChangeNotifier` ใฎไปฃๆฟใจใใฆๆไพใใใฎใ `Notifier` | |
// * `Notifier` ใใใค `ref` ใซใใไปใฎ Provider ใๆไพใใใชใใธใงใฏใใซใขใฏใปในใงใใ | |
// * `Notifier` ใฎ Provider ใจใชใใฎใ `NotifierProvider` ใงใใใกใใ `ConsumerWidget` | |
// ใ็ถๆฟใใ Widget ใใ `WidgetRef` ใไปใใฆใขใฏใปในใใ | |
// * `ref.watch(someNotifierProvider)` ใง `Notifier` ใฎใใค็ถๆ ๅคๅใซใใใชใใซใใงใใ | |
// * Provider ใฎ `select` ใงใ็ถๆ ใฎใใฃใซใฟใชใณใฐใใงใใ | |
// * `ref.read(someNotifierProvider.notifier)` ใง `Notifier` ใใฎใใฎใซใขใฏใปในใงใใ | |
// * `ref.listen(someNotifierProvider, ...)` ใง็ถๆ ๅคๅใๆค็ฅใงใใ | |
// * `ref.invalidate(someNotifierProvider)` ใง `Notifier` ใฎใชใใซใใใงใใ | |
// | |
// ProviderScope (has ChangeNotifier) | |
// โ ... | |
// โ ConsumerWidget (watch ChangeNotifier via Provider, Rebuild on ChangeNotifier change) | |
// โ Descendant Widget 1 (use state via ChangeNotifier) | |
// โ Button (update state via ChangeNotifier) | |
//================================================================================ | |
final class CounterNotifier extends riverpod.Notifier<int> { | |
@override | |
int build() { | |
// You can watch the other provider | |
// final hoge = ref.watch(otherStateProvider); | |
return 0; | |
} | |
void increment() => state++; | |
} | |
final counterNotifierProvider = | |
riverpod.NotifierProvider<CounterNotifier, int>(() { | |
return CounterNotifier(); | |
}); | |
final class Case8Page extends riverpod.ConsumerWidget { | |
const Case8Page({super.key}); | |
@override | |
Widget build(BuildContext context, riverpod.WidgetRef ref) { | |
debugPrint('Case8Page build'); | |
final counter = ref.read(counterNotifierProvider.notifier); | |
ref.listen(counterNotifierProvider.select((count) => count ~/ 10), | |
(_, next) { | |
ScaffoldMessenger.of(context).showSnackBar( | |
SnackBar(content: Text('Count is a multiple of 10 : $next')), | |
); | |
}); | |
return Center( | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
CountConsumerWidget(), | |
CountDoubleConsumerWidget(), | |
EvenOddConsumerWidget(), | |
const SizedBox(height: 8), | |
FilledButton( | |
onPressed: () => counter.increment(), | |
child: const Text('+'), | |
), | |
const SizedBox(height: 4), | |
FilledButton( | |
onPressed: () => ref.invalidate(counterNotifierProvider), | |
child: const Text('Reset'), | |
), | |
], | |
), | |
); | |
} | |
} | |
final class CountConsumerWidget extends riverpod.ConsumerWidget { | |
const CountConsumerWidget({super.key}); | |
@override | |
Widget build(BuildContext context, riverpod.WidgetRef ref) { | |
final count = ref.watch(counterNotifierProvider); | |
return Container( | |
color: Colors.cyan, | |
padding: EdgeInsets.all(8), | |
child: Text('CountConsumerWidget\nCount = $count'), | |
); | |
} | |
} | |
final class CountDoubleConsumerWidget extends riverpod.ConsumerWidget { | |
const CountDoubleConsumerWidget({super.key}); | |
@override | |
Widget build(BuildContext context, riverpod.WidgetRef ref) { | |
final countDouble = | |
ref.watch(counterNotifierProvider.select((count) => count * 2)); | |
return Container( | |
color: Colors.lime, | |
padding: EdgeInsets.all(8), | |
child: Text('CountDoubleConsumerWidget\nCount ร 2 = $countDouble'), | |
); | |
} | |
} | |
final class EvenOddConsumerWidget extends riverpod.ConsumerWidget { | |
const EvenOddConsumerWidget({super.key}); | |
@override | |
Widget build(BuildContext context, riverpod.WidgetRef ref) { | |
final isEven = | |
ref.watch(counterNotifierProvider.select((count) => count % 2 == 0)); | |
return Container( | |
color: Colors.yellow, | |
padding: EdgeInsets.all(8), | |
child: Text('EvenOddConsumerWidget\nCount is ${isEven ? 'even' : 'odd'}'), | |
); | |
} | |
} | |
//================================================================================ | |
// Others : https://github.com/temoki/flutter_state_management | |
//================================================================================ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment