性能优化
通过到目前为止我们所看到的一切,我们已经可以构建一个功能齐全的应用程序。 但是,您可能对性能有疑问。
在本页中,我们将介绍一些可能优化代码的提示和技巧。
在进行任何优化之前,请确保对您的应用程序进行基准测试。 优化所增加的复杂性可能不值得微小的收益。
使用 "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) {
// Instead of writing:
// String name = ref.watch(provider).firstName!;
// We can write:
String name = ref.watch(exampleProvider.select((it) => it.firstName));
// This will cause the widget to only listen to changes on "firstName".
return Text('Hello $name');
}
}
您可以根据需要多次调用 select
。
您可以为您想要的每个属性自由调用一次。
所选属性希望是不可变的对象。
返回 List
然后改变该列表不会触发重建。
使用 select
会稍微减慢单个读取操作的速度,
并稍微增加代码的复杂性。
如果那些“其他属性”很少改变,那么可能不值得使用它。
选择异步属性
考虑一种情况,如果您尝试优化一个监听其他提供者程序的提供者程序, 其他提供者程序很可能是异步的。
通常,您可以使用 ref.watch(anotherProvider.future)
来获取该值。
问题是,select
将应用于 AsyncValue
- 这不是您可以等待的事情。
为此,您可以使用 selectAsync
。它是异步代码所独有的,
并且允许对提供者程序发出的数据执行 select
操作。
它的用法与 select
类似,但返回一个 Future
类型:
Object? example(ExampleRef ref) async {
// Wait for a user to be available, and listen to only the "firstName" property
final firstName = await ref.watch(
userProvider.selectAsync((it) => it.firstName),
);
// TODO use "firstName" to fetch something else
}