質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Q&A

解決済

1回答

1516閲覧

【Flutter】 【Riverpod】 StateNotifierを用いたリストの更新ができない

royput0323

総合スコア1

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

0グッド

0クリップ

投稿2023/03/27 10:22

実現したいこと

・riverpodを用いた状態管理をしたい。

前提

サンプルアプリを作成し、FlutterのRiverpodの勉強をしています。
riverpodを用いてリストの状態管理をおこなっているのですが、
下記、add_training_view.dart内100行目のexistingMenu.descriptionが更新されません。

期待する動作としては、リストをタップ後、表示されるダイアログ内のメニューをタップすると、
リストの値が更新されることです。

なぜリストの値は更新されないのでしょうか。

発生している問題

エラーメッセージなどは特に出力されていません。

該当のソースコード

dart

1///main.dart 2 3import 'package:flutter/material.dart'; 4import 'package:google_fonts/google_fonts.dart'; 5import 'package:hooks_riverpod/hooks_riverpod.dart'; 6import 'package:wordle/screens/addtraining/add_training_view.dart'; 7 8void main() { 9 runApp(const ProviderScope(child: MyApp())); 10} 11 12class MyApp extends StatelessWidget { 13 const MyApp({Key? key}) : super(key: key); 14 15 16 Widget build(BuildContext context) { 17 return MaterialApp( 18 darkTheme: ThemeData.dark(), 19 themeMode: ThemeMode.dark, 20 theme: ThemeData( 21 colorScheme: ColorScheme.fromSeed(seedColor: Colors.green.shade300), 22 textTheme: GoogleFonts.sawarabiGothicTextTheme(), 23 useMaterial3: true, 24 ), 25 home: const Home(), 26 ); 27 } 28}

dart

1///menu.dart 2 3import 'package:flutter/foundation.dart' show immutable; 4import 'package:hooks_riverpod/hooks_riverpod.dart'; 5import 'package:uuid/uuid.dart'; 6 7const _uuid = Uuid(); 8 9/// A read-only description of a menu-item 10 11class Menu { 12 Menu({ 13 final String? id, 14 required this.bodyPart, 15 required this.description, 16 }) : id = id ?? const Uuid().v4(); 17 18 final String id; 19 final String bodyPart; 20 final String description; 21 22 Menu copyWith({String? id, String? bodyPart, String? description}) { 23 return Menu( 24 id: id ?? this.id, 25 bodyPart: bodyPart ?? this.bodyPart, 26 description: description ?? this.description, 27 ); 28 } 29 30 31 String toString() { 32 return 'Menu(id: $id, bodyPart:$bodyPart ,description: $description)'; 33 } 34} 35 36/// An object that controls a list of [Menu]. 37class MenuList extends StateNotifier<List<Menu>> { 38 MenuList() : super([]); 39 40 void add(String bodyPart, String description) { 41 state = [ 42 ...state, 43 Menu( 44 id: _uuid.v4(), 45 bodyPart: bodyPart, 46 description: description, 47 ), 48 ]; 49 } 50 51 void edit({ 52 required String id, 53 required String bodyPart, 54 required String description, 55 }) { 56 state = [ 57 for (final menu in state) 58 if (menu.id == id) 59 menu.copyWith( 60 id: id, 61 bodyPart: menu.bodyPart, 62 description: menu.description, 63 ) 64 else 65 menu, 66 ]; 67 } 68 69 void remove(Menu target) { 70 state = state.where((menu) => menu.id != target.id).toList(); 71 } 72}

dart

1//add_training_view.dart 2 3import 'package:flutter/material.dart'; 4import 'package:hooks_riverpod/hooks_riverpod.dart'; 5import 'package:uuid/uuid.dart'; 6import 'menu.dart'; 7 8final List<Map<String, dynamic>> allMenu = [ 9 {'id': 1, 'bodyPart': '胸', 'description': 'ベンチプレス'}, 10 {'id': 2, 'bodyPart': '背中', 'description': 'ラットプルダウン'}, 11]; 12 13final bodyPartList = allMenu.map((menu) => menu['bodyPart']).toSet().toList(); 14 15final bodyPartDescriptionList = bodyPartList.map((bodyPart) { 16 final descriptions = allMenu 17 .where((menu) => menu['bodyPart'] == bodyPart) 18 .map((menu) => menu['description']) 19 .toList(); 20 return { 21 'bodyPart': bodyPart, 22 'descriptions': descriptions, 23 }; 24}).toList(); 25 26final menuListProvider = StateNotifierProvider<MenuList, List<Menu>>((ref) { 27 return MenuList(); 28}); 29 30class Home extends ConsumerWidget { 31 const Home({Key? key}) : super(key: key); 32 33 34 Widget build(BuildContext context, WidgetRef ref) { 35 final menus = ref.watch(menuListProvider); 36 return Scaffold( 37 appBar: AppBar( 38 title: const Text('test'), 39 ), 40 body: GestureDetector( 41 onTap: () => FocusScope.of(context).unfocus(), 42 child: Scaffold( 43 body: ListView( 44 padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 40), 45 children: [ 46 if (menus.isNotEmpty) const Divider(height: 0), 47 for (final menu in menus) 48 Dismissible( 49 key: ValueKey(menu.id), 50 onDismissed: (_) { 51 ref.read(menuListProvider.notifier).remove(menu); 52 }, 53 child: ProviderScope( 54 overrides: [ 55 _currentMenu.overrideWithValue(menu), 56 ], 57 child: const MenuItem(), 58 ), 59 ), 60 ], 61 ), 62 ), 63 ), 64 floatingActionButton: FloatingActionButton( 65 onPressed: () async { 66 final menu = await createOrUpdateMenuDialog( 67 context, 68 ); 69 if (menu != null) { 70 final newMenu = ref.read(menuListProvider.notifier); 71 newMenu.add(menu.bodyPart, menu.description); 72 } 73 }, 74 child: const Icon(Icons.add), 75 ), 76 ); 77 } 78} 79 80final _currentMenu = Provider<Menu>((ref) => throw UnimplementedError()); 81 82class MenuItem extends ConsumerWidget { 83 const MenuItem({Key? key}) : super(key: key); 84 85 86 Widget build(BuildContext context, WidgetRef ref) { 87 final existingMenu = ref.watch(_currentMenu); 88 return Center( 89 child: InkWell( 90 child: Container( 91 decoration: BoxDecoration( 92 color: Colors.black, 93 border: Border.all(color: Colors.black), 94 borderRadius: BorderRadius.circular(10)), 95 width: 200, 96 height: 70, 97 child: Padding( 98 padding: const EdgeInsets.all(5), 99 child: Center( 100 child: Text(existingMenu.description), 101 ), 102 ), 103 ), 104 onTap: () async { 105 final selectedMenu = 106 await createOrUpdateMenuDialog(context, existingMenu); 107 if (selectedMenu != null) { 108 ref.read(menuListProvider.notifier).edit( 109 id: existingMenu.id, 110 bodyPart: selectedMenu.bodyPart, 111 description: selectedMenu.description, 112 ); 113 } 114 }, 115 ), 116 ); 117 } 118} 119 120Future<Menu?> createOrUpdateMenuDialog( 121 BuildContext context, [ 122 Menu? existingMenu, 123]) { 124 return showDialog( 125 context: context, 126 builder: (context) { 127 return SimpleDialog( 128 children: <Widget>[ 129 SizedBox( 130 width: 300, 131 height: 500, 132 child: ListView.builder( 133 shrinkWrap: true, 134 itemCount: bodyPartDescriptionList.length, 135 itemBuilder: (context, index) { 136 final item = bodyPartDescriptionList[index]; 137 final bodyPart = item['bodyPart']; 138 final descriptions = item['descriptions']; 139 return Padding( 140 padding: const EdgeInsets.fromLTRB(15, 10, 15, 0), 141 child: Column( 142 children: <Widget>[ 143 Container( 144 decoration: BoxDecoration( 145 border: Border.all(color: Colors.white), 146 borderRadius: BorderRadius.circular(10), 147 color: Colors.black, 148 ), 149 width: double.infinity, 150 child: Padding( 151 padding: const EdgeInsets.fromLTRB(10, 2, 0, 2), 152 child: Text(bodyPart), 153 ), 154 for (final description in descriptions) 155 InkWell( 156 key: ValueKey(description), 157 child: Padding( 158 padding: const EdgeInsets.fromLTRB(20, 2, 5, 2), 159 child: Container( 160 decoration: BoxDecoration( 161 border: Border( 162 bottom: BorderSide(), 163 ), 164 ), 165 child: Text(description), 166 ), 167 ), 168 ), 169 onTap: () { 170 final selectedMenu = allMenu.firstWhere( 171 (menu) => menu['description'] == description); 172 Navigator.of(context).pop( 173 Menu( 174 id: existingMenu != null 175 ? existingMenu.id 176 : const Uuid().v4(), 177 bodyPart: selectedMenu['bodyPart'], 178 description: selectedMenu['description'], 179 ), 180 ); 181 }, 182 ), 183 ], 184 ), 185 ); 186 }, 187 ), 188 ), 189 ], 190 ); 191 }, 192 ); 193}

補足情報(FW/ツールのバージョンなど)

[√] Flutter (Channel master, 3.9.0-16.0.pre.8, on Microsoft Windows [Version 10.0.22621.1413], locale ja-JP)
[√] Windows Version (Installed version of Windows is version 10 or higher)
[√] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
[√] Chrome - develop for the web
[√] Visual Studio - develop for Windows (Visual Studio Community 2022 17.4.3)
[√] Android Studio (version 2021.3)
[√] VS Code (version 1.76.2・
[√] Connected device (4 available)
[√] Network resources

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

editメソッドの実装間違いでは。

dart

1 void edit({ 2 required String id, 3 required String bodyPart, 4 required String description, 5 }) { 6 state = [ 7 for (final menu in state) 8 if (menu.id == id) 9 menu.copyWith( 10 id: id, 11 bodyPart: bodyPart, 12 description: description, 13 ) 14 else 15 menu, 16 ]; 17 }

投稿2023/03/27 23:57

ta.fu

総合スコア1667

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

royput0323

2023/03/28 16:26

ご回答ありがとうございます。無事解決しました。 初歩的な見落としでした、、
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問