flutter - 使用 Flutter Provider 包 Selector 小部件重建不必要的小部件
问题描述
当我使用依赖于该类的所有小部件更新ChangeNotifier
类实例变量时,将重新构建(好像我使用的是 a而不是小部件)。如果我使用小部件和相关参数正确更新实例变量,则仅根据更改的数据更新小部件Provider.of<T>(context, listen: true).value
Selector
Consumer
Selector
Provider.of<T>(context, listen: false).value
Selector
selector:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(AppMain());
class ModState with ChangeNotifier {
int _counter0 = 0;
int get counter0 => _counter0;
set counter0(int _value) {
_counter0 = _value;
notifyListeners();
}
int _counter1 = 0;
int get counter1 => _counter1;
set counter1(int _value) {
_counter1 = _value;
notifyListeners();
}
int get counter012 => (_counter0 + _counter1);
static ModState of(BuildContext context, {bool listen = true}) =>
Provider.of<ModState>(context, listen: listen);
}
class AppMain extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [ChangeNotifierProvider(builder: (_) => ModState())],
child: MaterialApp(home: Scaffold(
// Wrap in Builder Widget to clarify context
body: Builder(builder: (context) {
return SafeArea(
child: Column(children: <Widget>[
Row(
children: <Widget>[
Tooltip(
message: 'Update counter 0, rebuild counter 0 Text widget',
child: RaisedButton(
onPressed: () {
// Counterintuitively, user Provider.of<mode>(context, listen: false) to avoid rebuilding all children
ModState.of(context, listen: false).counter0++;
debugPrint(
'Counter0: button pressed ${ModState.of(context, listen: false).counter0}');
},
child: Text('Update 0, rebuild 0'),
),
),
Selector<ModState, int>(
selector: (_, _state) => _state.counter0,
builder: (_, _data, __) {
debugPrint(
'Counter0, builder invoked ${ModState.of(context, listen: false).counter0}');
return Text(
'$_data / ${ModState.of(context, listen: false).counter012}');
},
)
],
),
Row(
children: <Widget>[
Tooltip(
message: 'Update counter 1, rebuild counter 1 Text widget',
child: RaisedButton(
onPressed: () {
// Counterintuitively, user Provider.of<mode>(context, listen: false) to avoid rebuilding all children
ModState.of(context, listen: false).counter1++;
debugPrint(
'Counter1: button pressed ${ModState.of(context, listen: false).counter1}');
},
child: Text('Update 1, rebuild 1'),
),
),
Selector<ModState, int>(
selector: (_, _state) => _state.counter1,
builder: (_, _data, __) {
debugPrint(
'Counter1, builder invoked ${ModState.of(context, listen: false).counter1}');
return Text(
'$_data / ${ModState.of(context, listen: false).counter012}');
},
)
],
),
]));
}))));
}
}
虽然我现在的代码有效,但listen: false
就我对该参数的理解而言,使用该参数是违反直觉的。我想了解原因,以便总体上改进我的代码
解决方案
从这篇文章中提到的内容来看,Selector
正在按预期工作。如文档中所述,小部件将在selector(BuildContext, A)
. 这里似乎发生的是整个Widget build()
被重建。再说一次,如果 Widgets 上显示的数据是正确的并且没有性能问题,那么它是可以通过的。但是,如果您想阻止重建,您可能需要重新考虑 Provider 在页面上的布局方式。
推荐阅读
- node.js - 有没有办法在用户属性上查询 keycloak 用户?
- android - Android 工具栏菜单项不可点击
- html5-video - Pytest 断言错误。在 html5 中 - 视频播放器
- javascript - 有没有办法在 Coffeescript 中使用纯 Javascript?
- javascript - 百里香叶转义字符
- javascript - 开发工具 JS 调试:在任何地方评估定义值的中断
- c# - EF 和 NPGSQL 之间的 DateTimeOffset 精度不匹配
- android - 在旧版本上调用新方法不起作用
- sql - 这个日期时间比较在 MSSQL 中的评估结果是什么?
- java - 如何使用 iTextPDF 5.5 在单元格周围添加自定义文本边框