Sparround

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.

dart
// ❌ 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.

SituationApproach
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