0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Flutter】Riverpod + MVVM実装例

Last updated at Posted at 2024-07-17

■MVP
->プレゼンターが能動的にViewを更新しに行く

  • Model = ビジネスロジック+データアクセス
  • Presenter = アプリケーションロジック+Viewの更新
  • View = UI制御

■MVVM
->データバインディングでViewModelの値がViewに反映される

  • Model = ビジネスロジック+データアクセス
  • ViewModel = アプリケーションロジック
  • View = UI制御

■Riverpod

  • Provider = データの管理、提供者
    -> ViewModelはProviderを使ってデータを操作
  • Consumer:データの使用者
    -> ViewはConsumerWidgetを継承してデータを監視しておくと、Providerからデータが渡ってくる(データバインディング)

■実装例

dart models/todo.dart
// Model
// データクラス
class Todo {
  const Todo({required this.id, required this.title, this.isCompleted = false});

  final String id;
  final String title;
  final bool isCompleted;
}

dart view_models/todos_view_model.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../models/todo.dart';

// ViewModel
// ProviderとViewModel

final todosViewModelProvider =
    StateNotifierProvider<TodosViewModel, List<Todo>>((ref) {
  return TodosViewModel();
});

class TodosViewModel extends StateNotifier<List<Todo>> {
  // 初期状態として空のリストを追加
  TodosViewModel() : super([]);

  void addTodo(Todo todo) {
    state = [...state, todo];
  }

  void addTodoByTitle(String title) {
    addTodo(Todo(id: "$title${state.length + 1}", title: title));
  }

  void toggleTodoStatus(String id) {
    // 完了フラグを反転させる
    state = state.map((todo) {
      if (todo.id == id) {
        return Todo(
            id: todo.id, title: todo.title, isCompleted: !todo.isCompleted);
      }
      return todo;
    }).toList();
  }
}

dart main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mvvm_riverpod_test/view_models/todos_view_model.dart';
import 'models/todo.dart';

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: TodosPage(),
    );
  }
}

class TodosPage extends ConsumerWidget {
  TodosPage({super.key});

  TextEditingController controller = TextEditingController();

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // データの監視
    List<Todo> todos = ref.watch(todosViewModelProvider);
    return Scaffold(
      appBar: AppBar(
        title: const Text('TODO'),
      ),
      body: ListView.builder(
        // ListView.builderは以下のカウント数分ループ
        itemCount: todos.length + 1,
        itemBuilder: (context, index) {
          if (index == 0) {
            // 一つ目の要素はテキストフィールド
            return ListTile(
              title: TextField(controller: controller),
              trailing: ElevatedButton(
                onPressed: () {
                  ref
                      .read(todosViewModelProvider.notifier)
                      .addTodoByTitle(controller.text);
                  controller.clear();
                },
                child: const Text('登録'),
              ),
            );
          }
          final todo = todos[index - 1];
          return ListTile(
            title: Text(todo.title),
            trailing: Checkbox(
              value: todo.isCompleted,
              onChanged: (bool? newValue) {
                ref
                    .read(todosViewModelProvider.notifier)
                    .toggleTodoStatus(todo.id);
              },
            ),
          );
        },
      ),
    );
  }
}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?