🐳
[Flutter / Riverpod] StateNotifierProviderが推奨される理由と、Todoアプリのサンプル
はじめに
状態管理にChangeNotifierProviderを使用していましたが、Riverpodのドキュメントには下記のような記述が
可能な限り StateNotifierProvider を使用してください。
ChangeNotifierProvider の使用はミュータブルなステート管理を行う必然性がある場合に限定してください。
特別な理由がない限り、Modelクラスはimmutable[1]であったほうが予期せぬ動作を防ぐことができるため、
状態管理にもChangeNotifierではなくStateNotifierを使用した方が良いそうです
参考
上記ドキュメントを参考に、Todoアプリのサンプル作成の手順を記します
手順
- パッケージインストール
$ flutter pub add state_notifier
$ flutter pub add flutter_hooks
$ flutter pub add hooks_riverpod
- コード
- Modelクラス
Freezedでの生成も可[5]
todo.dart
// ドキュメントから引用(copyWithメソッドは今回使わないため除外)
class Todo {
const Todo({required this.id, required this.description});
final String id;
final String description;
}
- ViewModelクラス
todo_view_model.dart
class TodosNotifier extends StateNotifier<List<Todo>> {
TodosNotifier(): super([
// 初期値として適当なデータを入れています
Todo(id: '0', description: 'メモ0'),
Todo(id: '1', description: 'メモ1'),
Todo(id: '2', description: 'メモ2'),
]);
void addTodo(Todo todo) {
// stateのみ変更の処理をしているが、DBの操作もここで追記必要
state = [...state, todo];
}
void removeTodo(String todoId) {
// stateのみ変更の処理をしているが、DBの操作もここで追記必要
state = [
for (final todo in state)
if (todo.id != todoId) todo,
];
}
}
final todosProvider = StateNotifierProvider<TodosNotifier, List<Todo>>((ref) {
return TodosNotifier();
});
- Viewクラス
todo_page.dart
class TodoPage extends ConsumerWidget {
const TodoPage({Key? key}) : super(key: key);
Widget build(BuildContext context, WidgetRef ref) {
List<Todo> todos = ref.watch(todosProvider);
return Scaffold(
appBar: AppBar(
title: Text('TODO'),
),
body: SingleChildScrollView(
child: ListView(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
children: [
for (final todo in todos)
ListTile(
title: Text(todo.description),
trailing: IconButton(
icon: Icon(
Icons.delete,
color: Colors.red,
),
onPressed: () {
ref.read(todosProvider.notifier).removeTodo(todo.id);
},
),
),
],
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
ref.read(todosProvider.notifier).addTodo(
// 適当なデータを渡しています
Todo(
id: '${ref.read(todosProvider.notifier).state.length}',
description:
'メモ${ref.read(todosProvider.notifier).state.length}'
),
);
},
),
);
}
}
おわりに
まず完成イメージ
Riverpodでの状態管理を知った時は、StateNotifier?、ChangeNotifier?って感じでしたが、
少しメリットが理解できてきました。
ModelクラスをFreezedで生成する方法について別記事に載せているので、参考にしていただけますと幸いです。
Discussion