Flutter入门 - 状态管理
概述
从命令式编程框架(iOS、Android)到声明式编程(Flutter、vue), 比如 Flutter 有大量的 State 需要来进行管理,数据共享的时候,
分类
- 短时状态
某些简单的数据变化,只需要使用 statefulWidget 的 state 类自己管理即可
- 应用状态AppState
比如用户信息,全局性的数据信息,需要选择全局状态管理的方式
共享状态管理
InheritedWidget
定义一个共享数据的 InheritedWidget
,需要继承自 InheritedWidget
- 需要定义一个
of
静态方法,通过传入context
开始去查找祖先
的数据
class ShareWidget extends InheritedWidget {
//共享的 counter 数据
final int counter;
ShareWidget({this.counter, Widget child}) : super(child: child);
static ShareWidget of(BuildContext context) {
//沿着 context 往上查找最近的祖先 widget
return context.dependOnInheritedWidgetOfExactType();
}
@override
bool updateShouldNotify(covariant ShareWidget oldWidget) {
//是否需要通知数据变更
return this.counter != oldWidget.counter;
}
}
其他 widget 使用
@override
Widget build(BuildContext context) {
// 通过调用 of 静态方法拿到 “ShareWidget”
int _counter = ShareWidget.of(context).counter;
return Container(
child: Text("$_counter"),
);
}
Provider
官方推荐的全局状态管理工具
dependencies:
provider:^4.0.4
三个概念
- ChangeNotifier: 真正数据(状态)存放的地方
- ChangeNotifierProvider: widget树中提供数据的地方,会在其中创建对应的 ChangeNotifier
- Consumer: Widget 树中需要使用数据(状态)的地方
Provider 的基本用法
1.1 创建 provider
继承自 ChangeNotifier
class ViewModelProvider extends ChangeNotifier {
// 1.创建自己想要共享的数据
int _counter = 100;
int get counter => _counter;
set counter(int value) {
_counter = value;
notifyListeners();
}
}
1.2 插入 provider
在应用顶层放入 ChangeNotifierProvider
, 这样全局都可以使用 ViewModelProvider
void main() {
runApp(ChangeNotifierProvider(
create: (ctx) => ViewModelProvider(), child: HomePage()));
}
1.3 使用数据
1.3.1 Provider.of
int _counter = Provider.of<ViewModelProvider>(context).counter;
1.3.2 Consumer
- 使用 Consumer 包裹要使用共享数据的 widget
- builder 会返回三个参数
-
context
返回的是当前树的位置
-
provider
ChangeNotifier对应的实例,可以直接使用 provider 中的数据
-
child
目的是防止 child 被重复 build
- 当然使用 Consumer 的话,builder 所返回的 widget(例如demo中的FloatingActionButton) 仍然会被重复 build, 所以引入
Seletor
floatingActionButton: Consumer<ViewModelProvider>(
child: Icon(Icons.add),
//builder 会返回三个参数 context、provider、child
builder: (cxt, provider, child) {
return FloatingActionButton(
child: child,
onPressed: () {
setState(() {
provider.counter++;
});
},
);
},
),
1.3.3 Selector
关键参数
- 1.泛型参数<A,S>
-
- A: 我们这次要使用的 provider
-
- S: 转换之后的数据类型
- 2.seletor 回调函数
-
- 转换的回调函数,没有转换的话,可以直接返回 Provider 的实例
- 3.是否需要 rebuild
Selector({
Key? key,
required ValueWidgetBuilder<S> builder,
required S Function(BuildContext, A) selector,
ShouldRebuild<S>? shouldRebuild,
Widget? child,
})
floatingActionButton: Selector<ViewModelProvider, ViewModelProvider>(
selector: (cxt, provider) => provider,
shouldRebuild: (pre, next) => false,
builder: (cxt, provider, child) {
print("Selector build");
return FloatingActionButton(
onPressed: () {
provider.counter++;
},
child: child,
);
},
),
1.3.4 MultiProvider
开发中肯定不止一个 provider,不可能全部嵌套在 runApp中,因此使用 MultiProvider
可以定义一个 dart 类专门存放 providers
List<SingleChildWidget> providers = [
ChangeNotifierProvider(
create: (ctx) => Provider1(),
),
ChangeNotifierProvider(
create: (ctx) => Provider2(),
),
];
void main() {
runApp(
MultiProvider(
// 使用
providers: providers,
child: HomePage(),
),
);
}
使用小结
* 1.创建自己想要共享的数据 Provider extends ChangeNotifier
* 2.在应用顶层修改 runApp 添加 ChangeNotifierProvider
* 3.在其他位置使用共享数据
* 1)Provider.of<ViewModelProvider>(context)
* 2) Consumer (相对推荐)
* 3) Selector
* 4.使用 MultiProvider 管理多个共享状态
转载自:https://juejin.cn/post/7002623603715866637