Menu
CoddyTech

두 화면, 하나의 모델

Coddy Flutter 여정의 상태 관리 섹션에 포함된 레슨. 27개 중 13번째.

두 화면이 공유하는 데이터에서 Provider의 장점이 드러납니다. 설정 화면에서 이름을 변경하면 홈 화면에 이름이 표시되며, 두 화면은 서로 어떤 것도 전달하지 않습니다.

Provider가 어디에 위치하는지가 중요합니다. MaterialApp은 Navigator를 포함하고 있으며, 화면을 푸시하면 각 화면은 home 안이 아니라 그 옆에 추가됩니다.

ChangeNotifierProvider        <- above MaterialApp: every screen finds it
  MaterialApp
    Navigator
      HomePage
      SettingsScreen          <- pushed next to HomePage

HomePage를 Provider로 감싸면 HomePage에만 적용됩니다. 푸시된 화면은 그 아래에 있지 않으므로 모델을 찾을 수 없습니다. Provider를 main의 MaterialApp 위에 두면 모든 화면이 Provider를 공유합니다.

다른 화면에 두 번째 ChangeNotifierProvider를 추가해 오류를 해결하지 마세요. 그러면 두 번째 모델이 만들어집니다. 오류는 사라지지만, 화면들은 더 이상 아무것도 공유하지 않습니다.

challenge icon

챌린지

중급

기어를 누르고 이름을 입력한 다음 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'),
            ),
          ],
        ),
      ),
    );
  }
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

상태 관리의 모든 레슨

직접 연습해 보세요: 온라인 Flutter 컴파일러