Provider'dan Riverpod'a: Eski Durumu Taşıma
Mevcut ChangeNotifier ve Provider kodunu derleme sırasında güvenli provider grafiğine sahip Riverpod koduna dönüştürün.
Provider'dan Riverpod'a: Eski Durumu Taşıma, CoddyKit'te ücretsiz bir Flutter Mobile Development dersidir. Bu, 4 dersinin 1. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, Flutter Mobile Development öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. Flutter Mobile Development kursu toplamda 4 dersten oluşur.
Bu dersin bazı bölümleri henüz çevrilmemiş olup İngilizce olarak gösterilmektedir.
Why Migrate to Riverpod?
The classic provider package solved dependency injection in Flutter, but it has real weaknesses you have probably hit in production:
- Runtime crashes — calling
context.read<T>()for a type that was never provided throws aProviderNotFoundExceptionat runtime, not compile time. - BuildContext coupling — you can only read providers where you have a
BuildContext. - No combining — depending on one
ChangeNotifierfrom another is awkward and error-prone.
Riverpod is a rewrite by the same author. Providers are top-level globals that the compiler can verify, so a missing dependency becomes a compile error. This lesson walks you through migrating a legacy ChangeNotifier + Provider app to Riverpod 2.0, piece by piece.
The Legacy Code We Are Migrating
Here is a typical legacy counter feature using ChangeNotifier. It exposes a value and a method that calls notifyListeners(). This is the pattern we will convert step by step.
Notice that the state (_count) and the mutation logic live together inside a class that extends ChangeNotifier.
// LEGACY — provider package
import 'package:flutter/foundation.dart';
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
void reset() {
_count = 0;
notifyListeners();
}
}How the Legacy Model Was Wired Up
In the old setup you register the model with ChangeNotifierProvider high in the widget tree, then read it via context.watch / context.read. The problem: if you forget to register it, the app compiles fine and crashes only when that screen opens.
// LEGACY wiring
void main() {
runApp(
ChangeNotifierProvider(
create: (_) => CounterModel(),
child: const MyApp(),
),
);
}
// In a widget:
final count = context.watch<CounterModel>().count;
context.read<CounterModel>().increment();Step 1 — Install Riverpod and Add ProviderScope
Add flutter_riverpod to pubspec.yaml. The single most important wiring change is to wrap your app in a ProviderScope. This is the container that stores the state of every provider — it replaces the nest of ChangeNotifierProvider widgets at the root.
- Old: many provider widgets wrapping
MyApp. - New: one
ProviderScope. Providers themselves are declared as globals, not in the tree.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(
const ProviderScope(
child: MyApp(),
),
);
}Step 2 — ChangeNotifier becomes Notifier
Riverpod 2.0 introduces Notifier as the modern, type-safe replacement for ChangeNotifier. The differences:
- You hold state in a single
statefield instead of private fields + getters. - You never call
notifyListeners()— reassigningstaterebuilds listeners automatically. - The
build()method returns the initial state.
Here is the migrated counter as a Notifier<int>:
import 'package:flutter_riverpod/flutter_riverpod.dart';
class CounterNotifier extends Notifier<int> {
@override
int build() => 0; // initial state
void increment() => state = state + 1;
void reset() => state = 0;
}
final counterProvider = NotifierProvider<CounterNotifier, int>(
CounterNotifier.new,
);Step 3 — Read State in the UI with ConsumerWidget
Replace context.watch/context.read with a WidgetRef. The cleanest path is to make your widget a ConsumerWidget, which adds a ref parameter to build.
ref.watch(provider)— subscribe and rebuild on change (use inbuild).ref.read(provider.notifier)— get the notifier to call methods (use in callbacks).
class CounterScreen extends ConsumerWidget {
const CounterScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Scaffold(
body: Center(child: Text('Count: $count')),
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(counterProvider.notifier).increment(),
child: const Icon(Icons.add),
),
);
}
}watch vs read — The Migration Trap
The most common migration bug is using the wrong access method. Map the old API to the new one carefully:
context.watch<T>()→ref.watch(provider)(rebuilds the UI)context.read<T>()in a callback →ref.read(provider.notifier)(no rebuild)
Rule: never call ref.watch inside an onPressed callback — it will not behave as expected and can cause unnecessary rebuilds. Use ref.read for one-off actions, ref.watch for values displayed in the UI.
Step 4 — Migrating Async State (FutureProvider)
Legacy apps often load data inside a ChangeNotifier with manual isLoading/error booleans. Riverpod replaces all of that with AsyncValue and a FutureProvider — loading and error states are modeled for you.
The UI then uses AsyncValue.when to render data, loading, and error branches exhaustively.
final userProvider = FutureProvider<User>((ref) async {
final repo = ref.watch(userRepositoryProvider);
return repo.fetchCurrentUser();
});
// In a ConsumerWidget:
final asyncUser = ref.watch(userProvider);
return asyncUser.when(
data: (user) => Text(user.name),
loading: () => const CircularProgressIndicator(),
error: (e, st) => Text('Error: $e'),
);Step 5 — Combining Providers (No More ProxyProvider)
In the old package, making one model depend on another required ProxyProvider and careful ordering. In Riverpod, a provider simply calls ref.watch on another provider inside its body. Dependencies are explicit, type-safe, and reactive.
Below, a derived provider recomputes automatically whenever cartProvider changes — no manual subscription, no notifyListeners chains.
final cartProvider =
NotifierProvider<CartNotifier, List<Item>>(CartNotifier.new);
// Derived state — recomputes when the cart changes
final cartTotalProvider = Provider<double>((ref) {
final items = ref.watch(cartProvider);
return items.fold(0.0, (sum, item) => sum + item.price);
});A Standalone Taste of Reactive Derivation in Dart
You do not need Flutter to understand Riverpod's core idea: derived values recompute from their inputs. This pure-Dart snippet models the same fold-the-cart logic used in cartTotalProvider, so you can run and verify the math an online judge would compute.
class Item {
final String name;
final double price;
Item(this.name, this.price);
}
double cartTotal(List<Item> items) =>
items.fold(0.0, (sum, item) => sum + item.price);
void main() {
final cart = [
Item('Coffee', 3.50),
Item('Bagel', 2.25),
Item('Juice', 4.00),
];
print('Items: ${cart.length}');
print('Total: \$${cartTotal(cart).toStringAsFixed(2)}');
}Step 6 — Incremental Migration Strategy
You rarely rewrite a whole app at once. A safe, incremental plan:
- Wrap once: add
ProviderScopeat the root immediately — it coexists with the oldproviderpackage. - Leaf-first: migrate self-contained features (settings, theme, counters) before tangled ones.
- Bridge if needed: a Riverpod provider can read legacy data, and a legacy widget can stay until its screen is converted.
- Convert widgets: change
StatelessWidget→ConsumerWidgetandStatefulWidget→ConsumerStatefulWidgetas you touch each screen. - Delete the old
ChangeNotifierProviderand theproviderdependency only when nothing references them.
Quick Check — watch vs read
Test your understanding of the most error-prone part of the migration.
Recap — From Provider to Riverpod
You migrated a legacy ChangeNotifier + Provider feature to Riverpod 2.0:
- Wrapped the app in a single ProviderScope instead of nested provider widgets.
- Turned
ChangeNotifierinto a Notifier with astatefield and nonotifyListeners(). - Swapped
context.watch/readforref.watch(display) andref.read(provider.notifier)(actions) inside a ConsumerWidget. - Modeled async with FutureProvider +
AsyncValue.when, and combined providers viaref.watchinstead ofProxyProvider. - Followed a leaf-first, incremental path so the two systems coexist during the transition.
The payoff: a compile-safe provider graph where a missing dependency is a build error, not a production crash.
Yapay zeka eğitmeniyle Dart öğren — ücretsiz
Tarayıcında gerçek kod yaz ve çalıştır, 7/24 yapay zeka eğitmeninden anında yardım al; web'de ya da uygulamada kaldığın yerden devam et.
- Kurslar
- 22
- Dersler
- 88
Sıkça Sorulan Sorular
“Provider'dan Riverpod'a: Eski Durumu Taşıma” dersi ücretsiz mi?
Evet — “Provider'dan Riverpod'a: Eski Durumu Taşıma” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve Flutter Mobile Development kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. Flutter Mobile Development kursu toplamda 4 dersten oluşur.
“Provider'dan Riverpod'a: Eski Durumu Taşıma” dersinde ne öğreneceğim?
Mevcut ChangeNotifier ve Provider kodunu derleme sırasında güvenli provider grafiğine sahip Riverpod koduna dönüştürün. Flutter Mobile Development ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.
Flutter Mobile Development öğrenmeye başlamak için deneyim gerekli mi?
Önceden deneyim gerekmez. CoddyKit'te Flutter Mobile Development, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 1. dersidir.
“Provider'dan Riverpod'a: Eski Durumu Taşıma” dersi ne kadar sürer?
Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.
Bu Flutter Mobile Development dersinde kod yazıp çalıştırabilir miyim?
Evet. Her Flutter Mobile Development dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.
Bu kursun tüm dersleri
- Provider'dan Riverpod'a: Eski Durumu Taşıma
- riverpod_generator ve @riverpod ile Kod Üretimi
- AsyncNotifier ve FutureProvider Veri İş Akışları
- Provider Kapsamı, Geçersiz Kılmalar ve ProviderObserver