Ana içeriğe atla

2.0'dan 3.0'a geçiş

Değişikliklerin listesi için lütfen Riverpod 3.0'da neler yeni sayfasına bakın.

Riverpod 3.0, kodunuzu güncellemenizi gerektirebilecek bir dizi kırıcı değişiklik getiriyor. Bunlar genel olarak nispeten küçük değişikliklerdir, ancak bu sayfayı dikkatle okumanızı öneririz.

bilgi

Bu geçişin sorunsuz olması amaçlanmıştır.
Belirsiz bir nokta varsa veya geçişi zor olan bir senaryoyla karşılaştıysanız, lütfen bir issue açın.

Geçişin mümkün olduğunca sorunsuz olması bizim için önemlidir; bu yüzden size yardımcı olmak, geçiş rehberini iyileştirmek, hatta geçişi kolaylaştıracak yardımcılar eklemek için elimizden geleni yapacağız.

Otomatik yeniden deneme

Riverpod 3.0 artık başarısız olan provider'ları varsayılan olarak otomatik olarak yeniden deniyor. Yani bir provider değerini hesaplamayı başaramazsa, başarılı olana kadar otomatik olarak yeniden denenecektir.

Genel olarak bu iyi bir şeydir; uygulamanızı geçici hatalara karşı daha dayanıklı hale getirir. Yine de bazı durumlarda bu davranışı devre dışı bırakmak/özelleştirmek isteyebilirsiniz.

Otomatik yeniden denemeyi global olarak devre dışı bırakmak için bunu ProviderContainer/ProviderScope üzerinde yapabilirsiniz:

void main() {
runApp(
ProviderScope(
// Hiçbir provider'ı asla yeniden deneme
retry: (retryCount, error) => null,
child: MyApp(),
),
);
}

Alternatif olarak, provider'ın retry parametresini kullanarak otomatik yeniden denemeyi provider bazında devre dışı bırakabilirsiniz:

final todoListProvider = NotifierProvider<TodoList, List<Todo>>(
TodoList.new,
// Bu provider'ı asla yeniden deneme
retry: (retryCount, error) => null,
);

Görünüm dışındaki provider'lar duraklatılır

Riverpod 3.0'da görünüm dışındaki provider'lar varsayılan olarak duraklatılır.

Şu anda bu davranışı global olarak devre dışı bırakmanın bir yolu yok, ancak duraklatma davranışını TickerMode widget'ını kullanarak consumer düzeyinde denetleyebilirsiniz.

class MyWidget extends StatelessWidget {

Widget build(BuildContext context) {
return TickerMode(
enabled: true, // Alt ağaçtaki hiçbir dinleyiciyi asla duraklatma.
child: Consumer(
builder: (context, ref, child) {
// Bu "watch", TickerMode kaldırılana kadar otomatik
// duraklatma davranışını izlemeyecek.
final value = ref.watch(myProvider);
return Text(value.toString());
},
),
);
}
}

StateProvider, StateNotifierProvider ve ChangeNotifierProvider yeni bir import'a taşındı

Riverpod 3.0'da StateProvider, StateNotifierProvider ve ChangeNotifierProvider "legacy" (eski) kabul edilir.
Kaldırılmadılar, ancak artık ana API'nin bir parçası değiller. Bunun amacı, yeni Notifier API'si lehine bunların kullanımını caydırmaktır.

Bunları kullanmaya devam etmek için import'larınızı aşağıdakilerden biriyle değiştirmeniz gerekir:

import 'package:hooks_riverpod/legacy.dart';
import 'package:flutter_riverpod/legacy.dart';
import 'package:riverpod/legacy.dart';

Provider'ların tamamı artık güncellemeleri filtrelemek için == kullanıyor

Önceden Riverpod, provider'lara gelen güncellemeleri filtreleme biçiminde tutarsızdı. Bazı provider'lar güncellemeleri filtrelemek için == kullanırken, bazıları identical kullanıyordu. Riverpod 3.0'da artık tüm provider'lar güncellemeleri filtrelemek için == kullanıyor.

Bu değişiklikten etkilenmenizin en olası yolu StreamProvider/StreamNotifier kullanmaktır; çünkü artık stream değerleri == ile filtrelenecek. İhtiyaç duyarsanız, davranışı özelleştirmek için Notifier.updateShouldNotify metodunu geçersiz kılabilirsiniz.

class TodoList extends StreamNotifier<Todo> {

Stream<Todo> build() => Stream(...);


bool updateShouldNotify(AsyncValue<Todo> previous, AsyncValue<Todo> next) {
// Özel uygulama
return true;
}
}

Bir Notifier kullanmadığınız senaryoda, provider'ınızı notifier karşılığına dönüştürebilirsiniz (Örneğin StreamProviderStreamNotifierProvider'a çevirmek gibi).

ProviderObserver'ın arayüzü biraz değişti

mutation'lar uğruna, ProviderObserver arayüzü biraz değişti.

ProviderContainer ve ProviderBase için iki ayrı parametre yerine, tek bir ProviderObserverContext nesnesi aktarılıyor. Bu nesne hem container'ı, hem provider'ı, hem de ek bilgileri (ilişkili mutation gibi) içerir.

Geçiş yapmak için observer'larınızın tüm metotlarını şu şekilde güncellemeniz gerekir:

class MyObserver extends ProviderObserver {
@override
- void didAddProvider(ProviderBase provider, Object? value, ProviderContainer container) {
+ void didAddProvider(ProviderObserverContext context, Object? value) {
// ...
}
}

Sadeleştirilmiş Ref ve kaldırılan Ref alt sınıfları

Sadeleştirme adına, Ref tip parametresini kaybetti ve tip parametresini kullanan tüm özellikler/metotlar Notifier'lara taşındı.

Daha somut olarak, ProviderRef.state, Ref.listenSelf ve FutureProviderRef.future sırasıyla Notifier.state, Notifier.listenSelf ve AsyncNotifier.future ile değiştirilmelidir.

// Önce:
final valueProvider = FutureProvider<int>((ref) async {
ref.listen(anotherProvider, (previous, next) {
ref.state++;
});

ref.listenSelf((previous, next) {
print('Log: $previous -> $next');
});

ref.future.then((value) {
print('Future: $value');
});

return 0;
});

// Sonra
class Value extends AsyncNotifier<int> {

Future<int> build() async {
ref.listen(anotherProvider, (previous, next) {
ref.state++;
});

listenSelf((previous, next) {
print('Log: $previous -> $next');
});

future.then((value) {
print('Future: $value');
});

return 0;
}
}
final valueProvider = AsyncNotifierProvider<Value, int>(Value.new);

Benzer şekilde, tüm Ref alt sınıfları kaldırıldı (bunlarla sınırlı olmamak üzere ProviderRef, FutureProviderRef vb.).

Bu, öncelikli olarak kod üretimini etkiler. MyProviderRef yerine artık doğrudan Ref kullanabilirsiniz:

@riverpod
-int example(ExampleRef ref) {
+int example(Ref ref) {
// ...
}

AutoDispose arayüzleri kaldırıldı.

Otomatik yok etme özelliği sadeleştirildi. Tüm arayüzlerin bir kopyasına dayanmak yerine, arayüzler birleştirildi. Kısacası, AutoDisposeProvider, AutoDisposeNotifier vb. yerine artık Provider, Notifier vb. var. Davranış aynı, ancak API sadeleşti.

Kolayca geçiş yapmak için, büyük/küçük harfe duyarlı bir değiştirme ile AutoDispose ifadesini (boş dize) ile değiştirebilirsiniz.

Notifier'ların family varyantı kaldırıldı

Bir önceki maddeye benzer şekilde, Notifier'ların family varyantı da kaldırıldı. Artık yalnızca Notifier/AsyncNotifier/StreamNotifier kullanıyoruz; FamilyNotifier/... ise kaldırıldı.

Geçiş yapmak için şunları değiştirmeniz gerekecek:

  • FamilyNotifier -> Notifier
  • FamilyAsyncNotifier -> AsyncNotifier
  • FamilyStreamNotifier -> StreamNotifier

Ardından şunları yapmanız gerekecek:

  • build metodundan parametreyi kaldırın
  • Notifier'ınıza bir kurucu (constructor) ekleyin

Bu geçişin bir örneği şöyledir:

final provider = NotifierProvider.family<CounterNotifier, int, String>(CounterNotifier.new);

-class CounterNotifier extends FamilyNotifier<int, String> {
+class CounterNotifier extends Notifier<int> {
+ CounterNotifier(this.arg);
+ final String arg;

@override
- int build(String arg) {
+ int build() {
// `arg`i gerektiği gibi kullanın
return 0;
}
}

Provider hataları artık ProviderException olarak yeniden fırlatılıyor

Riverpod 3.0'da tüm provider hataları ProviderException olarak yeniden fırlatılır. Yani bir provider değerini hesaplamayı başaramazsa, onu okumak orijinal hata yerine bir ProviderException fırlatacaktır.

Belirli hataları ele almak için orijinal hata tipine güveniyorduysanız bu sizi etkileyebilir. Geçiş yapmak için ProviderExceptionı yakalayıp orijinal hatayı içinden çıkarabilirsiniz:

try {
await ref.read(myProvider.future);
-} on NotFoundException {
- // NotFoundException'ı ele al
+} on ProviderException catch (e) {
+ if (e.exception is NotFoundException) {
+ // NotFoundException'ı ele al
+ }
}
bilgi

Bu yalnızca, böyle bir hatayı ele almak için açıkça try/catch'e güveniyorduysanız gereklidir.

Hataları kontrol etmek için [AsyncValue] kullanıyorsanız hiçbir şeyi değiştirmenize gerek yok:

AsyncValue<int> value = ref.watch(myProvider);
if (value.error is NotFoundException) {
// NotFoundException'ı ele al
// Bu bugün hâlâ çalışıyor
}