Appearance
setState
调用一个StatefulWidget的setState方法,会触发Widget的build方法,然后重新build子Widget。所以,你一定会在状态组件中,使用setState方法。当然如果你的StatefulWidget并没有使用setState方法,那么你一定要在StatelessWidget和StatefulWidget中做出选择。
异步更新
有时候,如果不使用FutureBuilder,同样会遇到在异步函数中调用setState触发build来更新UI。一方面我们不能保证setState的执行顺序,另一方面我们也不能保证执行的过程中,组件不被销毁,所以我们要对setState进行优化。在更新前,使用mounted校验组件是否被销毁。使用下面的代码,覆盖默认的setState方法,这样一来当组件被销毁时,放弃执行setState方法。这样也是短路逻辑之一。如果不这样做,运行的过程中,你也会看到不必要的报错。
dart
@override
void setState(fn) {
if (!mounted) {
return;
}
super.setState(fn);
}
将StatefulWidget构造成下面的组件
dart
import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
@override
void setState(fn) {
if (!mounted) {
return;
}
super.setState(fn);
}
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}
避免循环
setState方法会触发build方法,所以,在build方法中,不应该调用setState方法。否则会导致渲染死循环
先计算,在setState
状态计算和刷新UI是两个不同的过程,应该分开执行,这样可以避免UI阻塞。在setState方法中,不应该直接修改状态,而是应该先计算状态,然后再调用setState方法。 对于占用较大的计算,使用async/await,或者使用compute。待计算完成后,在刷新UI。
不过由于回调函数是在完成计算后,才刷新UI,所以只有较大运算逻辑时,且不使用FutureBuilder,才需要这样做。 如果只是:
dart
setState(() {
loaded = true;
});
之类的简单逻辑,则没有必要。
Statefulwidget 最小化单元
StatefulWidget应该尽量最小化。这样可以避免setState时,重绘过多的组件。