我有一个自定义的 appbar 类,我将标题作为其构造函数传递。
class MyAppBar extends StatelessWidget implements PreferredSizeWidget {
final String? title;
@override
Size get preferredSize => Size.fromHeight(AppBar().preferredSize.height);
const MyAppBar({super.key, this.title});
@override
Widget build(BuildContext context) {
return AppBar(title: Text(title ?? "CFlytics"));
}
}
现在,我在 ConsumerStatefulWidget 中使用 MyAppBar,并将“appbartitle”作为传递给它的状态变量。
当我使用 setState 更新 appbartitle 变量时,它根本不会更新 appbar 标题
class _MyHomePageState extends State<MyHomePage> {
String? appbartitle;
@override
Widget build(BuildContext context) {
final myData =ref.watch(someProvider);
return Scaffold(
appBar: MyAppBar(title: appbartitle),
body: myData.when(
data: (data) {
setState(() {appbartitle = "123";});
return ...;
},
loading: {return ...}
error: {return ...}
但是当我将 setState 行包装在 Future.delayed 中时,即使延迟为 0 毫秒,它也会按要求工作
Future.delayed(const Duration(milliseconds: 0), () {
setState(() {appbartitle = "new title";});
});
为什么会这样?实施这个的正确方法是什么?
首先,这个语法看起来像旧的 Riverpod,从这个意义上说, someprovider 将是一个 FutureProvider 。尽管如此,如果您这样做,我希望看到错误“在构建期间调用 setstate 或 markNeedsBuild()”。我认为它不起作用,因为您在 myData.when() 中调用 setstate ,它也有效地调用 setstate ,所有这些都在同一个同步进程中。 将其放置在 Future.delayed 中使其成为异步调用,该调用在事件循环中的同步任务之后进行调度。您可以在 Flutter 中查找事件队列、微任务队列和异步进程。 通过将其包装在 Future 中,您只需在 myData.when 处理完它自己的 setstate 后调用 setstate 即可。 Riverpod 有 ref.listen,这是在构建中使用来更新数据的更合适的方法。 或者,我会写这样的东西,以免更改太多代码。
@override
Widget build(BuildContext context) {
final myData =ref.watch(someProvider);
if(myData.hasValue){
appBarTitle = '123';
}
return Scaffold(
appBar: MyAppBar(title: appbartitle),
body: myData.when(
data: (data) {
//don't call setstate here
return ...;
},
loading: {return ...},
error: {return ...},),
);
}
尽管如此,您仍然需要处理加载和错误状态,并且当状态处于加载/错误状态时 myData.haveValue 可以为 true。