두 화면, 하나의 모델
Coddy Flutter 여정의 상태 관리 섹션에 포함된 레슨. 27개 중 13번째.
두 화면이 공유하는 데이터에서 Provider의 장점이 드러납니다. 설정 화면에서 이름을 변경하면 홈 화면에 이름이 표시되며, 두 화면은 서로 어떤 것도 전달하지 않습니다.
Provider가 어디에 위치하는지가 중요합니다. MaterialApp은 Navigator를 포함하고 있으며, 화면을 푸시하면 각 화면은 home 안이 아니라 그 옆에 추가됩니다.
ChangeNotifierProvider <- above MaterialApp: every screen finds it
MaterialApp
Navigator
HomePage
SettingsScreen <- pushed next to HomePageHomePage를 Provider로 감싸면 HomePage에만 적용됩니다. 푸시된 화면은 그 아래에 있지 않으므로 모델을 찾을 수 없습니다. Provider를 main의 MaterialApp 위에 두면 모든 화면이 Provider를 공유합니다.
다른 화면에 두 번째 ChangeNotifierProvider를 추가해 오류를 해결하지 마세요. 그러면 두 번째 모델이 만들어집니다. 오류는 사라지지만, 화면들은 더 이상 아무것도 공유하지 않습니다.
챌린지
중급기어를 누르고 이름을 입력한 다음 Save를 누르세요. provider가 HomePage만 감싸고 있기 때문에 앱에 오류가 표시됩니다.
ChangeNotifierProvider를MyApp바깥에서main안으로 옮겨MyApp을 감싸도록 하세요.
그러면 Ada를 저장했을 때 홈 화면에 Hello, Ada!가 표시됩니다.
직접 해보기
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Profile extends ChangeNotifier {
String _name = 'Guest';
String get name => _name;
void rename(String newName) {
_name = newName;
notifyListeners();
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: ChangeNotifierProvider(
create: (context) => Profile(),
child: const HomePage(),
),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
final profile = context.watch<Profile>();
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
actions: [
IconButton(
icon: const Icon(Icons.settings),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SettingsScreen()),
);
},
),
],
),
body: Center(
child: Text('Hello, ${profile.name}!', style: const TextStyle(fontSize: 32)),
),
);
}
}
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});
@override
State<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
final controller = TextEditingController();
@override
Widget build(BuildContext context) {
final profile = context.watch<Profile>();
return Scaffold(
appBar: AppBar(title: const Text('Settings')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Text('Signed in as ${profile.name}'),
const SizedBox(height: 16),
TextField(
controller: controller,
decoration: const InputDecoration(labelText: 'Your name'),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {
context.read<Profile>().rename(controller.text);
Navigator.pop(context);
},
child: const Text('Save'),
),
],
),
),
);
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
상태 관리의 모든 레슨
직접 연습해 보세요: 온라인 Flutter 컴파일러