Flutter-状态管理
InheritedWidget管理方式
MJYCounterWidget(
counter: _counter,
child: Column(
children: [MJYShowData01(), MJYShowData02()],
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
setState(() {
_counter++;
});
},
),
class MJYCounterWidget extends InheritedWidget {
// 1.共享的数据
int counter;
// 2.定义构造方法
MJYCounterWidget({required Widget child, required this.counter})
: super(child: child);
// 3.获取组建最近的当前的InheritedWidget
static MJYCounterWidget? of(BuildContext ctx) {
//沿着element数找到最近的MJYCounterElement,从element中取出widget对应的对象
//
return ctx.dependOnInheritedWidgetOfExactType();
}
@override
// 4.决定要不要回调State中的didChangeDependencies方法
// 如果返回为TRUE,执行依赖当前的InheritedWidget中的State中的didChangeDependencies
bool updateShouldNotify(covariant InheritedWidget oldWidget) {
// return true;
return oldWidget != counter;
}
}
class MJYShowData01 extends StatelessWidget {
@override
Widget build(BuildContext context) {
int? counter = MJYCounterWidget.of(context)?.counter;
return Card(
color: Colors.red,
child: Text("当前计数:$counter"),
);
}
}
class MJYShowData02 extends StatelessWidget {
@override
Widget build(BuildContext context) {
int? counter = MJYCounterWidget.of(context)?.counter;
return Container(
color: Colors.blue,
child: Text("当前计数:$counter"),
);
}
}
ProVider 官方推荐的全局状态管理工具
- 创建自己需要共享的数据
- 在我们应用程序的顶层使用ChangeNotifierProvider
- 在其他位置使用共享的数据
- 两种方式Consumer,使用Consumer会更多,当数据发生改变时因为不会重新构建build全部组件,只会重新构建Consumer的build
- 和Provider.of,会重新build整个的widget
- Selector:selector,1、对原有的数据进行转化,2、shouldRebuild,要不要重新构建数据模型
需要共享的数据
//with 相当于混入
class MJYCounterStore with ChangeNotifier {
// 快速生成getter/setter/toString/Construct/快捷键Command+n
int _counter = 100;
int get counter => _counter;
void increment() {
_counter++;
notifyListeners();
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
properties.add(IntProperty('count', counter));
}
set counter(int value) {
_counter = value;
// 通知所有的监听者
notifyListeners();
}
}
应用程度顶层使用
main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_)=>MJYCounterStore())
],
child: const MYApp(),
)
);
}
读取值
最简单的读取值的方式就是使用 BuildContext 上的扩展属性(由 provider 注入)。
context.watch<T>(),widget 能够监听到T类型的 provider 发生的改变。context.read<T>(),直接返回T,不会监听改变。context.select<T,R>(R cb(T value)),允许 widget 只监听T上的一部分内容的改变。
Scaffold(
appBar: AppBar(
title: Text("Provider"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
MJYShowData01(),
MJYShowData02(),
MJYShowData03()
],
),
),
///方式3
floatingActionButton: Selector<MJYCounterStore,MJYCounterStore>(
selector: (ctx,vm)=>vm,
shouldRebuild: (prev,next)=>false,
builder: (ctx,vm,child){
return FloatingActionButton(
onPressed: (){
vm.counter += 1;
},
child: child,
);
},
child: Icon(Icons.add),
),
///方式2
// floatingActionButton: FloatingActionButton(
// key: const Key('increment_floatingActionButton'),
//
// /// Calls `context.read` instead of `context.watch` so that it does not rebuild
// /// when [Counter] changes.
// onPressed: () => context.read<MJYCounterStore>().increment(),
// tooltip: 'Increment',
// child: const Icon(Icons.add),
// ),
)
- Consumer方式,可以部分更新
context.watch<T>(),widget 能够监听到T类型的 provider 发生的改变Provider.of<T>(context)这一静态方法,它的表现类似watch, 而在你为传入listen: false参数时(例如Provider.of<T>(context,listen: false)), 它的表现与read类似
class MJYShowData01 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// int counter = Provider.of<MJYCounterStore>(context).counter;
return Card(
color: Colors.red,
child: Consumer<MJYCounterStore>(
builder: (ctx, vm, child) {
return Text(
"当前计数:${vm.counter}",
style: Theme.of(context).textTheme.headline4);
},
)
);
}
}
class MJYShowData02 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// int counter = Provider.of<MJYCounterStore>(context).counter;
return Container(
color: Colors.blue,
child: Text(
'当前计数:${context.watch<MJYCounterStore>().counter}',
key: const Key('counterState'),
style: Theme.of(context).textTheme.headline4),
);
}
}
class MJYShowData03 extends StatelessWidget {
@override
Widget build(BuildContext context) {
int counter = Provider.of<MJYCounterStore>(context).counter;
return Container(
margin: EdgeInsets.only(top: 5),
color: Colors.green,
child: Text(
'当前计数:$counter',
key: const Key('counterState'),
style: Theme.of(context).textTheme.headline4),
);
}
}
效果