main.dart
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() {
setState(() {
// 폼이 summit 된후, 모든 폼 입력에 대해서 항상 validation 확인
autovalidateMode = AutovalidateMode.always;
});
final form = formKey.currentState;
if (form == null || !form.validate()) return;
form.save();
var result = context.read<AppProvider>().getResult(searchTerm!);
}
@override
Widget build(BuildContext context) {
final appState = context.watch<AppProvider>().state;
// build 에서 처리하면 문제가 발생한다. re-build 할때마다 else 문으로 계속 분기됨.
if (appState == AppState.success) {
WidgetsBinding.instance!.addPostFrameCallback((_) {
Navigator.push(context, MaterialPageRoute(
builder: (context) {
return const SuccessPage();
},
));
});
} else if (appState == AppState.error) {
WidgetsBinding.instance!.addPostFrameCallback((_) {
showDialog(
context: context,
builder: (context) {
return const AlertDialog(
content: Text('Something went wrong'),
);
},
);
});
}
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();
// 이걸 안해도 build 에서 AppState.error 를 확인하니, 동작하는거 처럼 보인다. 하지만 rebuild 시 오류 창을 무한 반복한다.
// rethrow;
}
}
}
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),
),
),
);
}
}
[참고자료] udemy - Flutter Provider Essential 코스 (Korean)
'Flutter > 07 State - Provider' 카테고리의 다른 글
[Flutter] StateNotifierProvider (0) | 2022.05.24 |
---|---|
[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 |