【ProviderとRiverpodの違い⑥】信頼性のあるパラメータ化機構の欠如
はじめに
前回に引き続き、今回もRiverpodのモチベーションについて解説していきます。
今回の記事では、「信頼性のあるパラメータ化機構の欠如」というセクションを掘り下げていきます。
信頼性のあるパラメータ化機構の欠如
公式ドキュメントの説明
Riverpod では、.family 修飾子を使用して "外部のパラメータをもとに一意の" provider を宣言できます。
実際、
.family
は Riverpod の最も強力な機能の 1 つであり、その革新の中心です。これにより、ロジックの単純化が可能になります。
Provider で同様のことを実装しようとすると、使いやすさとタイプセーフの両方を犠牲にする必要があります。
さらに、Provider では同様の
.autoDispose
機構を実装できないため、.family
の同等の実装を妨げることになります。最後に、前述のように、ウィジェットは
InheritedWidget
をリッスンするのを決して止めません。これにより、provider の状態が"動的にマウント"された場合、すなわちパラメータを使用して provider を構築する場合に、重大なメモリリークが発生します。
したがって、Provider に対する
.family
の同等の実装は現時点では根本的に不可能です。
Providerにおけるパラメータ化されたプロバイダーの課題
Providerを使用してパラメータに基づくプロバイダーを実装するとき、一般的にはファクトリーパターンなどを使用して複数のインスタンスを管理することがあります。
また、状態の自動破棄(autoDispose)のような機能を実装するのは困難で、不要な状態がメモリに残り続けることがあります。
例えば、以下の例では、UserProvider
を特定のユーザーIDに基づいて初期化していますが、異なるIDに基づいて複数のUserProvider
インスタンスを容易に管理する方法は提供されていません。
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class UserProvider with ChangeNotifier {
final String userId;
UserProvider(this.userId);
// User data fetch logic
}
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => UserProvider('user1')),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: Scaffold(body: Text('User Provider Example')));
}
}
Riverpodの.family修飾子による改善
Riverpodの.family
修飾子を使用すると、パラメータに基づいてプロバイダーを動的に生成し、それぞれのインスタンスを自動的に管理することができます。
これにより、ロジックの単純化が可能になり、使いやすさとタイプセーフを保ちながらプロバイダーを柔軟に利用できます。
以下の例では、userProvider
はuserId
をパラメータとして受け取り、それに基づいてユーザーデータを返します。
.family
修飾子により、異なるユーザーIDに対する呼び出しは自動的に管理され、.autoDispose
を使用することで、ウィジェットが不要になったときにプロバイダーの状態が自動的に破棄されます。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final userProvider = Provider.autoDispose.family<String, String>((ref, userId) {
// Return user data based on userId
return "Data for $userId";
});
void main() {
runApp(
ProviderScope(
child: MaterialApp(home: Home()),
),
);
}
class Home extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final userData = ref.watch(userProvider('user1'));
return Scaffold(body: Text(userData));
}
}
まとめ
Riverpodの.family
修飾子は、パラメータ化されたプロバイダーの管理を単純化し、Providerが直面する多くの問題を解決します。これにより開発者は、より少ないコードでより安全かつ効率的に状態管理ができるようになります。
次回、「副作用のトリガーが簡単でない」デュエルスタンバイ!