viewにボタンを二つ置いて、、
AutoDisposeFutureProviderFamilyでログイン処理って書けないのかなぁ、、 もう疲れた、、
AutoDisposeFutureProviderFamilyってログイン情報とかフィルタ条件を渡せば、使い勝手が良いように思うんだよね、、
いったい何がどうちがうんだ?
AutoDisposeFutureProviderを使う場合は AuthRequestをStateProviderにして参照可能にする→AuthRequestState LOGIN2ボタンでAuthRequestStateを更新する。 AutoDisposeFutureProviderはAuthRequestStateをwatchするようにしておく すると、AutoDisposeFutureProviderは再構築される AutoDisposeFutureProviderが再構築されると viewも再構築されるてのは、なんとなく理解できる
でも、 AutoDisposeFutureProviderFamilyを入れようとすると良く解らんナァ、、
import 'package:care_smile/data/auth_model.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:care_smile/request_api.dart'; final errorMessageProvider = StateProvider((ref) => ''); // ★StateNotifierとStateNotifierProviderでやる場合はこうかな? class LoginNotifier extends StateNotifier<LoginState> { LoginNotifier(this.ref) : super(const LoginState()); final Ref ref; //★ ここが気に入らない //データ読み込み処理 Future<LoginState> readData(name, password) async { LoginState loginState = await Repository().login(name, password) .onError((error, stackTrace) async { ref.watch(errorMessageProvider.notifier).state = "ログインに失敗しました"; throw Exception(error.toString()); }); state = state.copyWith( isSaseki: loginState.isSaseki, syokuinCode: loginState.syokuinCode, accessToken: loginState.accessToken, refreshToken: loginState.refreshToken, ); return loginState; } } final loginProvider = StateNotifierProvider((ref) => LoginNotifier(ref)); // ★StateProviderとAutoDisposeFutureProviderFamilyでやる場合はこうかな? final loginStateProvider = StateProvider((ref) => const LoginState()); AutoDisposeFutureProviderFamily<LoginState, AuthRequest> loginRequestFutureProvider = FutureProvider.autoDispose .family<LoginState, AuthRequest>( (ref, authRequest) async { LoginState loginState = await Repository().login(authRequest.name, authRequest.password) .onError((error, stackTrace) async { ref.watch(errorMessageProvider.notifier).state = "ログインに失敗しました"; throw Exception(error.toString()); }); ref.watch(loginStateProvider.notifier).state .copyWith( isSaseki: loginState.isSaseki, syokuinCode: loginState.syokuinCode, accessToken: loginState.accessToken, refreshToken: loginState.refreshToken, ); return loginState; } );
呼び出し側も書いてみる、、
import 'package:care_smile/data/auth_model.dart'; import 'package:care_smile/ui/schedule_list.dart'; import 'package:care_smile/request_api.dart'; import 'package:care_smile/provider/login_view_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import '../provider/login_view_model.dart'; class LoginApp extends StatelessWidget { const LoginApp({Key? key}) : super(key: key); // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'アプリ', theme: ThemeData( primarySwatch: Colors.blue, ), home: LoginPage(title: 'Login Page'), localizationsDelegates: [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], supportedLocales: const [ Locale("en"), Locale("ja"), ], ); } } class LoginPage extends HookConsumerWidget { LoginPage({Key? key, required this.title}) : super(key: key); final String title; final _userNameTextCtl = TextEditingController(); final _pwdTextCtl = TextEditingController(); final FocusNode _userNameFocusNode = FocusNode(); final FocusNode _passwordNameFocusNode = FocusNode(); @override Widget build(BuildContext context, WidgetRef ref) { final errorMessage = ref.watch(errorMessageProvider); final viewModel = ref.watch(loginProvider.notifier); return Scaffold( appBar: AppBar( title: Text(title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(errorMessage, style: const TextStyle(color: Colors.red)), TextField( controller: _userNameTextCtl, decoration: const InputDecoration( filled: true, labelText: 'Username', ), focusNode: _userNameFocusNode, ), const SizedBox(height: 10.0), TextField( controller: _pwdTextCtl, decoration: const InputDecoration( filled: true, labelText: 'Password', ), focusNode: _passwordNameFocusNode, obscureText: true, ), ButtonBar( children: <Widget>[ ElevatedButton( //★ ボタン1 child: const Text('LOGIN'), onPressed: () { viewModel.readData( _userNameTextCtl.text, _pwdTextCtl.text).then( (loginStatus) { debugPrint('LOGIN:' + loginStatus.accessToken); Navigator.push(context, MaterialPageRoute(builder: (context) => ScheduleList(loginStatus: loginStatus))); } ).onError((error, stackTrace) { // _userNameTextController.clear(); _pwdTextCtl.clear(); }); }), ElevatedButton( //★ ボタン2 child: const Text('LOGIN2'), onPressed: () { AuthRequest req = AuthRequest(name: _userNameTextCtl.text, password: _pwdTextCtl.text); final messageProvider = ref.watch(loginRequestFutureProvider(req)); //watchは変だな、、 messageProvider.when( data: (loginState) { debugPrint('LOGIN2:' + loginState.accessToken); }, error: (error, stackTrace) { Future(() { showDialog( context: context, builder: (_) { return AlertDialog( title: const Text( "認証に失敗しました。再ログインをお願いします。"), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text("OK")), ], ); }).then((_) { Navigator.pop(context); }); }); }, loading: () => const AspectRatio(aspectRatio: 0.01, child: CircularProgressIndicator(), ), ); }), ], ), ], ), ), ); } }