오늘은 Provider 구현시, 상태에 따라서 추가적인 액션이 필요한 경우에 대한 구조입니다.
개발환경 : 윈도우11, 안드로이드 스튜디오(Arctic Fox 2020.3.1 Patch 4), flutter 2.10
소스코드 - Release 33_ChangeNotifier_addListener2 · mike-bskim/provider_overview · GitHub
main.dart - submit 함수내에서 추가 액션을 구현
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'app_provider.dart';
import 'success_page.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<AppProvider>(
create: (_) => AppProvider(),
child: MaterialApp(
title: 'addListener of ChangeNotifier',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
AutovalidateMode autovalidateMode = AutovalidateMode.disabled;
String? searchTerm;
void submit() async {
setState(() {
// 폼이 summit 된후, 모든 폼 입력에 대해서 항상 validation 확인
autovalidateMode = AutovalidateMode.always;
});
final form = formKey.currentState;
if (form == null || !form.validate()) return;
form.save();
try {
var result = await context.read<AppProvider>().getResult(searchTerm!);
Navigator.push(context, MaterialPageRoute(
builder: (context) {
return const SuccessPage();
},
));
} catch (e) {
showDialog(
context: context,
builder: (context) {
return const AlertDialog(
content: Text('Something went wrong'),
);
},
);
}
}
@override
Widget build(BuildContext context) {
final appState = context.watch<AppProvider>().state;
return GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0),
child: Form(
key: formKey,
autovalidateMode: autovalidateMode,
child: ListView(
shrinkWrap: true,
children: [
TextFormField(
autofocus: true,
decoration: const InputDecoration(
border: OutlineInputBorder(),
label: Text('Search'),
prefixIcon: Icon(Icons.search),
),
validator: (String? value) {
if (value == null || value.trim().isEmpty) {
return 'Search term required';
}
return null;
},
onSaved: (String? value) {
searchTerm = value;
},
),
const SizedBox(height: 20.0),
ElevatedButton(
child: Text(
appState == AppState.loading
? 'Loading...'
: 'Get Result',
style: const TextStyle(fontSize: 24.0),
),
onPressed: appState == AppState.loading ? null : submit,
),
],
),
),
),
),
),
);
}
}
app_provider.dart
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
enum AppState {
initial,
loading,
success,
error,
}
class AppProvider with ChangeNotifier {
AppState _state = AppState.initial;
AppState get state => _state;
Future<void> getResult(String searchTerm) async {
_state = AppState.loading;
notifyListeners();
await Future.delayed(const Duration(seconds: 1));
try {
if (searchTerm == 'fail') {
throw 'Something went wrong';
}
_state = AppState.success;
notifyListeners();
} catch (e) {
_state = AppState.error;
notifyListeners();
rethrow; // 이걸 한번더 해줘야 호출한 main.dart 의 submit 함수에서도 오류수신가능, catch 문이 동작함.
}
}
}
success_page.dart
import 'package:flutter/material.dart';
class SuccessPage extends StatelessWidget {
const SuccessPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Success'),
),
body: const Center(
child: Text(
'Success',
style: TextStyle(fontSize: 48.0),
),
),
);
}
}
'Flutter > 07 State - Provider' 카테고리의 다른 글
[Flutter] Provider 상태에 따른 추가 액션(with addListener) (0) | 2022.05.23 |
---|---|
[Flutter] Provider 상태에 따른 추가 액션(without addListener) 오류 (0) | 2022.05.09 |
[Flutter] Provider - errors(Provider with Navigator.push) (0) | 2022.05.08 |
[Flutter] Provider - errors(provider with Dialog) (0) | 2022.05.08 |
[Flutter] Provider - errors(provider with StatefulWidget) (0) | 2022.05.08 |