Ana içeriğe atla

Provider/widget yeniden oluşturmaları nasıl azaltılır

Şimdiye kadar gördüklerimizle tamamen çalışan bir uygulama yazabilecek durumdayız. Yine de performans konusunda aklınıza bazı sorular takılmış olabilir.

Bu sayfada, kodunuzu optimize etmenize yardımcı olabilecek birkaç ipucuna değineceğiz.

DİKKAT

Herhangi bir optimizasyon yapmadan önce uygulamanızı mutlaka ölçümleyin. Optimizasyonların getirdiği ek karmaşıklık, elde edilen küçük kazanımlara değmeyebilir.

"select" ile widget/provider yeniden oluşturmalarını filtreleme

Fark etmiş olabileceğiniz gibi, ref.watch varsayılan olarak bir nesnenin herhangi bir özelliği değiştiğinde consumer'ların/provider'ların yeniden oluşturulmasına neden olur.
Örneğin, bir User dinleyip yalnızca "name" özelliğini kullansanız bile, "age" değiştiğinde consumer yeniden oluşturulur.

Ancak bir consumer özelliklerin yalnızca bir kısmını kullanıyorsa, diğer özellikler değiştiğinde widget'ın yeniden oluşturulmasını istemezsiniz.

Bunu provider'ların select özelliğini kullanarak sağlayabilirsiniz.
Bu durumda ref.watch artık nesnenin tamamını değil, yalnızca seçilen özellikleri döndürür.
Ve consumer'larınız/provider'larınız yalnızca bu seçilen özellikler değiştiğinde yeniden oluşturulur.

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) {
// Şunu yazmak yerine:
// String name = ref.watch(provider).firstName!;
// Şöyle yazabiliriz:
String name = ref.watch(provider.select((it) => it.firstName));
// Bu, widget'ın yalnızca "firstName" üzerindeki değişiklikleri dinlemesini sağlar.

return Text('Hello $name');
}
}
bilgi

selecti istediğiniz kadar çağırabilirsiniz. İhtiyaç duyduğunuz her özellik için bir kez çağırmakta serbestsiniz.

DİKKAT

Seçilen özelliklerin değişmez (immutable) olması beklenir. Bir List döndürüp ardından o listeyi değiştirmek yeniden oluşturmayı tetiklemez.

DİKKAT

select kullanmak tekil okuma işlemlerini bir miktar yavaşlatır ve kodunuzun karmaşıklığını çok az da olsa artırır. Söz konusu "diğer özellikler" nadiren değişiyorsa kullanmaya değmeyebilir.

Asenkron özellikleri seçme

Başka bir provider'ı dinleyen bir provider'ı optimize etmeye çalışıyorsanız, büyük ihtimalle o diğer provider asenkrondur.

Normalde değeri almak için ref.watch(anotherProvider.future) yazardınız.
Sorun şu ki select, await edemeyeceğiniz bir AsyncValue üzerinde uygulanır.

Bunun için selectAsync kullanabilirsiniz. Yalnızca asenkron koda özgüdür ve bir provider'ın yaydığı veri üzerinde select işlemi yapmanızı sağlar.
Kullanımı select ile benzerdir, ancak bunun yerine bir Future döndürür:

final provider = FutureProvider((ref) async {
// Bir kullanıcı hazır olana kadar bekleyin ve yalnızca "firstName" özelliğini dinleyin
final firstName = await ref.watch(
userProvider.selectAsync((it) => it.firstName),
);

// TODO "firstName" değerini başka bir şeyi getirmek için kullanın
});