Composition: ProxyProvider and dependencies
In a real app objects depend on each other: a repository on an API client, a view model on a repository. The Provider docs state the rule directly: don't create objects from values that can change over time inside `create` — use `ProxyProvider` for that.
The reason is simple: create runs only once. If you build the object from another provider's current value and that value later changes, your object is stuck with a stale dependency.
ProxyProvider<A, R> works through an update callback: when A changes, update runs again and R is refreshed. The previous parameter hands you the previous R so you can reuse the object instead of recreating it.
// ❌ create bir dəfə işləyir: auth token sonra dəyişsə, repository köhnə token ilə qalır.
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => AuthModel()),
Provider<TodoRepository>(
create: (context) => TodoRepository(context.read<AuthModel>().token),
),
],
child: const MyApp(),
);
// ✅ ProxyProvider: AuthModel bildiriş verdikdə update yenidən çağırılır.
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => AuthModel()),
ProxyProvider<AuthModel, TodoRepository>(
update: (_, auth, previous) => TodoRepository(auth.token),
),
],
child: const MyApp(),
);
// ✅ Notifier asılıdırsa: ChangeNotifierProxyProvider + previous ilə təkrar istifadə.
ChangeNotifierProxyProvider<TodoRepository, TodoListModel>(
create: (context) => TodoListModel(context.read<TodoRepository>()),
update: (_, repo, previous) => (previous ?? TodoListModel(repo))..updateRepository(repo),
);Building a dependent object right and wrong.
| Situation | Approach |
|---|---|
| The dependency never changes (API client, config) | A plain `Provider` with `context.read` inside `create` |
| The dependency changes over time (token, selected locale, user id) | `ProxyProvider` — `update` runs on every change |
| The dependent object is itself a `ChangeNotifier` | `ChangeNotifierProxyProvider` with `previous` for reuse |
| Two or more dependencies | `ProxyProvider2`…`ProxyProvider6` |
Riverpod's official comparison page puts it this way: the equivalent of ProxyProvider in Riverpod is simply calling ref.watch() inside a provider — when the value changes, the dependent provider is recomputed automatically. In an interview that comparison gives a concrete technical argument for "why Riverpod?": composition needs no separate provider kind.
📚 Sources and documentation
- package:provider — ProxyProviderofficialpub.dev
The "don't create objects from values that can change" rule is in the README.
- Provider vs Riverpod (official comparison)officialriverpod.dev
The ProxyProvider → ref.watch and ChangeNotifierProxyProvider → ref.listen mapping.
- Flutter architecture guide: layersofficialdocs.flutter.dev
The official rules about how repositories and services may depend on each other.