お久しぶりです。みやかわです。
Flutter で遊んでいる私ですが、最近 reverpod を覚えて開発が随分楽になりました。
MVVMもどきで開発をすすめているのですが、reverpod + StateNotifier で state の値を受け取るときにある問題に遭遇しました。
その回避方法についてメモ程度に書いていきます。
起こった問題
前提
以下のような Textfiled に文字を書くとの text wdiget に書いた文字が反映されるアプリをつくたいとします。
provider は以下のような感じにします。
setText() で TextFiled で書いた文字を state に反映させています。
final appProvider = StateNotifierProvider<AppProvider, AppState>( (_) => AppProvider(AppRepository()), ); class AppProvider extends StateNotifier { AppProvider(this.repository) : super(const AppState()); final AppRepository repository; void setText(String text) { state = state.copyWith(text: text); } }
state は以下のような感じにします。
text という変数を保持しているだけです。
※ freezed を使ってます
part 'app_state.freezed.dart'; part 'app_state.g.dart'; @freezed class AppState with _$AppState { const factory AppState({@Default('') String text}) = _AppState; factory AppState.fromJson(Map<String, dynamic> json) => _$AppStateFromJson(json); }
view は以下のような感じです。
TextFiled の onChange で入力文字を受け取り、受け取った文字を provider に流しています。
そして Text では、state を受け取っています。
class HomePage extends HookConsumerWidget { const HomePage({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { final notifier = ref.read(appProvider.notifier); final state = ref.watch(appProvider); return Scaffold( body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Padding( padding: const EdgeInsets.all(30), child: TextField( onChanged: (value) => notifier.setText(value), ), ), Text(state.text) ], ), ), ); } }
ちなみに repository はapi通信をするとかファイル操作等をしないのでテキトーです。
class AppRepository {}
遭遇した問題
上記のプログラムをVSCode で書くと、view側で以下のエラーがでます。
The property 'text' can't be unconditionally accessed because the receiver can be 'null'. Try making the access conditional (using '?.') or adding a null check to the target ('!').dartunchecked_use_of_nullable_value
text は null の可能性あるから条件付きアクセスするかnullチェックしてねと言われます。
エラーメッセージに従ってnullチェックをしてもエラーは消えません。
Object型には text なんと存在しねーと言われます。
The getter 'text' isn't defined for the type 'Object'. Try importing the library that defines 'text', correcting the name to the name of an existing getter, or defining a getter or field named 'text'.dartundefined_getter
対策する
修正
エラーメッセージ2つ目にかかれていることを実装します。
つまり、Provider に state になにが入っているかを教えてあげます。
以下のようにproviderを修正します。
@@ -2,7 +2,7 @@ import 'package:flutter_playground/repository/app_repository.dart'; import 'package:flutter_playground/state/app_state.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -final appProvider = StateNotifierProvider( +final appProvider = StateNotifierProvider<AppProvider, AppState>( (_) => AppProvider(AppRepository()), );
結果
無事エラー対応ができていることを確認。
実行してみるとちゃんとTextFildで書いた文字がTextで反映されています。
参考
・https://qiita.com/sou0506/items/f75a2b44d66d95faea4c
コメント