性能优化
通过到目前为止我们所看到的一切,我们已经可以构建一个功能齐全的应用程序。 但是,您可能对性能有疑问。
在本页中,我们将介绍一些可能优化代码的提示和技巧。
在进行任何优化之前,请确保对您的应用程序进行基准测试。 优化所增加的复杂性可能不值得微小的收益。
使用 "select" 过滤小部件或提供者程序的重建。
您已经注意到,默认情况下,只要对象的任何属性发生更改,
使用 ref.watch
都会导致消费者程序或提供者程序进行重建。
例如,观察 User
并仅使用其 "name",
如果 "age" 发生变化,仍然会导致消费者程序重建。
但如果您的使用者仅使用属性的子集, 您希望避免在其他属性更改时重建小部件。
这可以通过使用提供者程序的 select
功能来实现。
这样做时,ref.watch
将不再返回完整对象,
而是返回选定的属性。
现在,仅当这些选定的属性发生变化时,
您的消费者程序或提供者程序才会重建。
- riverpod_generator
- riverpod
class User {
late String firstName, lastName;
}
User example(Ref 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');
}
}
class User {
late String firstName, lastName;
}
final provider = Provider(
(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(provider.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
类型:
- riverpod_generator
- riverpod
Object? example(Ref 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
}
final provider = FutureProvider((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
});