跳到主要內容

效能最佳化

透過到目前為止我們所看到的一切,我們已經可以構建一個功能齊全的應用程式。 但是,您可能對效能有疑問。

在本頁中,我們將介紹一些可能最佳化程式碼的提示和技巧。

警告

在進行任何最佳化之前,請確保對您的應用程式進行基準測試。 最佳化所增加的複雜性可能不值得微小的收益。

使用 "select" 過濾小部件或提供者程式的重建。

您已經注意到,預設情況下,只要物件的任何屬性發生更改, 使用 ref.watch 都會導致消費者程式或提供者程式進行重建。
例如,觀察 User 並僅使用其 "name", 如果 "age" 發生變化,仍然會導致消費者程式重建。

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

這可以透過使用提供者程式的 select 功能來實現。
這樣做時,ref.watch 將不再返回完整物件, 而是返回選定的屬性。
現在,僅當這些選定的屬性發生變化時, 您的消費者程式或提供者程式才會重建。

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');
}
}
資訊

您可以根據需要多次呼叫 select。 您可以為您想要的每個屬性自由呼叫一次。

警告

所選屬性希望是不可變的物件。 返回 List 然後改變該列表不會觸發重建。

警告

使用 select 會稍微減慢單個讀取操作的速度, 並稍微增加程式碼的複雜性。
如果那些“其他屬性”很少改變,那麼可能不值得使用它。

選擇非同步屬性​

考慮一種情況,如果您嘗試最佳化一個監聽其他提供者程式的提供者程式, 其他提供者程式很可能是非同步的。

通常,您可以使用 ref.watch(anotherProvider.future) 來獲取該值。
問題是,select 將應用於 AsyncValue - 這不是您可以等待的事情。

為此,您可以使用 selectAsync。它是非同步程式碼所獨有的, 並且允許對提供者程式發出的資料執行 select 操作。
它的用法與 select 類似,但返回一個 Future 型別:


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
}