Kod üretimi hakkında
Kod üretimi, bizim yerimize kod üretmesi için bir araç kullanma fikridir. Dart'ta bunun dezavantajı, bir uygulamayı "derlemek" için fazladan bir adım gerektirmesidir. Yine de Dart ekibi bu soruna olası bir çözüm üzerinde çalıştığı için, bu sorun yakın gelecekte ortadan kalkabilir.
Riverpod bağlamında kod üretimi, bir "provider" tanımlamak için kullanılan sözdizimini biraz değiştirmekle ilgilidir. Örneğin şunun yerine:
final fetchUserProvider = FutureProvider.autoDispose.family<User, int>((
ref,
userId,
) async {
final json = await http.get('api/user/$userId');
return User.fromJson(json);
});
Kod üretimi kullanarak şöyle yazardık:
Future<User> fetchUser(Ref ref, {required int userId}) async {
final json = await http.get('api/user/$userId');
return User.fromJson(json);
}
Riverpod kullanırken kod üretimi tamamen isteğe bağlıdır. Riverpod'u kod üretimi olmadan kullanmak da tümüyle mümkündür. Bununla birlikte Riverpod kod üretimini benimser ve kullanılmasını önerir.
Riverpod'un kod üreticisinin nasıl kurulacağı ve kullanılacağı hakkında bilgi için
Başlarken sayfasına bakın. Dokümantasyonun kenar çubuğundan kod üretimini etkinleştirmeyi unutmayın.Kod üretimi kullanmalı mıyım?
Riverpod'da kod üretimi isteğe bağlıdır. Bunu göz önünde bulundurarak, onu kullanmalı mısınız yoksa kullanmamalı mısınız diye merak ediyor olabilirsiniz.
Yanıt şu: Yalnızca başka şeyler için zaten kod üretimi kullanıyorsanız. (bkz. Freezed, json_serializable vb.)
Dart ekibi "macros" adlı bir özellik üzerinde çalışırken, Riverpod'u kullanmanın önerilen
yolu kod üretimiydi. Ne yazık ki bu özellik iptal edildi.
Kod üretimi pek çok fayda sağlasa da şu anda hâlâ oldukça yavaştır. Dart ekibi kod üretiminin performansını iyileştirmek üzere çalışıyor, ancak bunun ne zaman kullanılabilir olacağı ve ne kadar iyileşme sağlayacağı belirsiz. Dolayısıyla, projenizde halihazırda kod üretimi kullanmıyorsanız, yalnızca Riverpod için kod üretimine başlamak muhtemelen zahmete değmez.
Öte yandan pek çok uygulama, Freezed veya json_serializable gibi paketlerle zaten kod üretimi kullanıyor. Bu durumda projeniz muhtemelen kod üretimi için zaten hazırdır ve Riverpod'u kullanmak basit olacaktır.
Kod üretimi kullanmanın faydaları nelerdir?
"Riverpod'da kod üretimi isteğe bağlıysa, neden kullanayım?" diye merak ediyor olabilirsiniz.
Paketlerde her zaman olduğu gibi: Hayatınızı kolaylaştırmak için. Bunlar arasında (bunlarla sınırlı olmamak üzere) şunlar yer alır:
- Daha iyi sözdizimi; daha okunabilir/esnek ve daha düşük bir öğrenme eğrisi.
- Provider'ın türü hakkında endişelenmenize gerek yok. Siz mantığınızı yazın, Riverpod sizin için en uygun provider'ı seçsin.
- Sözdizimi artık "kirli bir global değişken" tanımlıyormuşuz gibi görünmüyor. Bunun yerine özel bir fonksiyon/sınıf tanımlıyoruz.
- Provider'lara parametre aktarmak artık kısıtlı değil. Family kullanmak ve tek bir konumsal parametre aktarmakla sınırlı kalmak yerine, artık istediğiniz parametreyi aktarabilirsiniz. Buna adlandırılmış parametreler, isteğe bağlı parametreler ve hatta varsayılan değerler de dahildir.
- Riverpod ile yazılan kodun durumu koruyan hot-reload'u.
- Hata ayıklayıcının kullandığı ek üstverinin üretilmesi sayesinde daha iyi hata ayıklama.
Sözdizimi
Bir provider tanımlamak:
Kod üretimi kullanarak bir provider tanımlarken şu noktaları akılda tutmak faydalıdır:
- Provider'lar ya işaretlenmiş (annotated) bir fonksiyon ya da
işaretlenmiş bir sınıf olarak tanımlanabilir. İkisi hemen hemen aynıdır,
ancak sınıf tabanlı provider'ın avantajı, dış nesnelerin provider'ın durumunu değiştirmesini
(yan etkiler) sağlayan public metotlar içerebilmesidir. Fonksiyonel provider'lar,
yalnızca bir
buildmetodu olan sınıf tabanlı bir provider yazmanın sözdizimsel kısaltmasıdır ve bu nedenle kullanıcı arayüzü tarafından değiştirilemezler. - Dart'ın tüm asenkron ilkelleri (Future, FutureOr ve Stream) desteklenir.
- Bir fonksiyon asenkron olarak işaretlendiğinde, provider hata/yükleniyor durumlarını otomatik olarak yönetir ve bir AsyncValue sunar.
| Fonksiyonel (Public metotlar kullanarak yan etki gerçekleştiremez) | Sınıf Tabanlı (Public metotlar kullanarak yan etki gerçekleştirebilir) | |
|---|---|---|
| Senkron | | |
| Asenkron - Future | | |
| Asenkron - Stream | | |
autoDispose'u etkinleştirme/devre dışı bırakma:
Kod üretimi kullanıldığında provider'lar varsayılan olarak autoDispose'dur. Yani kendilerine bağlı
bir dinleyici kalmadığında (ref.watch/ref.listen) kendilerini otomatik olarak yok ederler.
Bu varsayılan ayar Riverpod'un felsefesiyle daha uyumludur. Kod üretimi kullanılmayan varyantta,
package:provider'dan geçiş yapan kullanıcıları gözetmek için autoDispose başlangıçta varsayılan olarak kapalıydı.
autoDispose'u devre dışı bırakmak isterseniz, bunu anotasyona keepAlive: true aktararak yapabilirsiniz.
// AutoDispose provider (keepAlive is false by default)
String example1(Ref ref) => 'foo';
// Non autoDispose provider
(keepAlive: true)
String example2(Ref ref) => 'foo';
Bir provider'a parametre aktarmak (family):
Kod üretimi kullanıldığında, bir provider'a parametre aktarmak için artık family değiştiricisine
ihtiyacımız yok.
Bunun yerine provider'ımızın ana fonksiyonu; adlandırılmış, isteğe bağlı veya varsayılan değerli
parametreler dahil olmak üzere istediğiniz sayıda parametre alabilir.
Ancak bu parametrelerin yine de tutarlı bir == davranışına sahip olması gerektiğini unutmayın.
Yani ya değerler önbelleğe alınmalı ya da parametreler =='i geçersiz kılmalıdır.
| Fonksiyonel | Sınıf Tabanlı |
|---|---|
| |
Kod üretimi kullanmayan varyanttan geçiş:
Kod üretimi kullanmayan varyantta, provider'ınızın türünü elle belirlemeniz gerekir. Kod üretimi kullanan varyanta geçerken karşılık gelen seçenekler şunlardır:
| Provider | |
| Önce | |
| Sonra | |
| NotifierProvider | |
| Önce | |
| Sonra | |
| FutureProvider | |
| Önce | |
| Sonra | |
| StreamProvider | |
| Önce | |
| Sonra | |
| AsyncNotifierProvider | |
| Önce | |
| Sonra | |
| StreamNotifierProvider | |
| Önce | |
| Sonra | |