跳到主要内容

性能优化

通过到目前为止我们所看到的一切,我们已经可以构建一个功能齐全的应用程序。 但是,您可能对性能有疑问。

在本页中,我们将介绍一些可能优化代码的提示和技巧。

警告

在进行任何优化之前,请确保对您的应用程序进行基准测试。 优化所增加的复杂性可能不值得微小的收益。

使用 "select" 过滤小部件或提供者程序的重建。

您已经注意到,默认情况下,只要对象的任何属性发生更改, 使用 ref.watch 都会导致消费者程序或提供者程序进行重建。
例如,观察 User 并仅使用其 "name", 如果 "age" 发生变化,仍然会导致消费者程序重建。

但如果您的使用者仅使用属性的子集, 您希望避免在其他属性更改时重建小部件。

这可以通过使用提供者程序的 select 功能来实现。
这样做时,ref.watch 将不再返回完整对象, 而是返回选定的属性。
现在,仅当这些选定的属性发生变化时, 您的消费者程序或提供者程序才会重建。

class User {
late String firstName, lastName;
}


User example(ExampleRef ref) => User()
..firstName = 'John'
..lastName = 'Doe';

class ConsumerExample extends ConsumerWidget {

Widget build(BuildContext context, WidgetRef ref) {
// 替代这种写法:
// String name = ref.watch(provider).firstName!;
// 我们可以写:
String name = ref.watch(exampleProvider.select((it) => it.firstName));
// 这将导致 widget 只监听 "firstName" 上的更改。

return Text('Hello $name');
}
}
信息

您可以根据需要多次调用 select。 您可以为您想要的每个属性自由调用一次。

警告

所选属性希望是不可变的对象。 返回 List 然后改变该列表不会触发重建。

警告

使用 select 会稍微减慢单个读取操作的速度, 并稍微增加代码的复杂性。
如果那些“其他属性”很少改变,那么可能不值得使用它。

选择异步属性​

考虑一种情况,如果您尝试优化一个监听其他提供者程序的提供者程序, 其他提供者程序很可能是异步的。

通常,您可以使用 ref.watch(anotherProvider.future) 来获取该值。
问题是,select 将应用于 AsyncValue - 这不是您可以等待的事情。

为此,您可以使用 selectAsync。它是异步代码所独有的, 并且允许对提供者程序发出的数据执行 select 操作。
它的用法与 select 类似,但返回一个 Future 类型:


Object? example(ExampleRef ref) async {
// 等待 user 可用,并只监听 "firstName" 属性
final firstName = await ref.watch(
userProvider.selectAsync((it) => it.firstName),
);

// TODO 使用 "firstName" 获取其他信息
}