Youtube 코딩셰프님의 강의를 요약 정리한 글이다. dart 언어나 이론 부분은 자바와 유사하여 대부분 제외하였고, flutter 기초 위주로 정리한다.
https://www.youtube.com/@codingchef
ChangeNotifier
어떤 데이터를 담을지에 대한 클래스에 근거해서 provider들을 만든다. 지난 글에서 Provider.of<FishModel>(context)를 사용한 것처럼 FishModel이 변화하는 데이터로 지정된다.
이 변화하는 데이터를 추적하는 역할을 ChangeNotifier가 한다. 아래처럼 with 구문을 통해 mixin으로 FishModel에 ChangeNotifier를 추가해줄 수 있다.
import 'package:flutter/cupertino.dart';
class FishModel with ChangeNotifier{
final String name;
final int number;
final String size;
FishModel({required this.name, required this.number, required this.size});
}
extends(상속) 과 mixin의 차이
강의에서의 예시처럼, 상속은 강한 결합관계를 갖는다. 또한 Dart에서는 Java처럼 다중 상속을 허용하지 않기 때문에 여러 클래스들을 상속할 수 없다.
그러나 class 대신 mixin으로 정의한 클래스는 다른 클래스에서 with 구문으로 얼마든지 여러 개 참조할 수 있다. 그리고 단순히 기능을 추가한다는 개념으로 이해하면 될 것 같다.
ChangeNotifier의 notifyListeners 메서드를 사용하면 ChangeNotifier를 Listen하고 있는 모든 위젯들에게 데이터의 변경 사실을 알려줄 수 있게 된다. 그리고 addListener 라는 메서드를 통해 데이터의 변경 사실을 알고 싶은 위젯들에서 콜백 메서드로 등록하면 값의 변경을 알 수 있게 되는 구조이다. 또한 addListener는 자동으로 제거되지 않기 때문에 removeListener라는 메서드를 통해서 필요없는 addListener를 dispose 시켜주어야한다.
ChangeNotifierProvider
위 번거로움 때문에 ChangeNotifierProvider를 사용한다.
아래처럼 FishModel에 메서드를 하나 만든다. ChangeNotifier를 mixin으로 받아왔으므로 notifyListeners 메서드를 사용할 수 있다.
import 'package:flutter/cupertino.dart';
class FishModel with ChangeNotifier{
final String name;
int number;
final String size;
FishModel({required this.name, required this.number, required this.size});
void changeFishNumber() {
number++;
notifyListeners();
}
}
그리고 main.dart 파일에서 Provider 대신 ChangeNotifierProvider를 적용한다.
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => FishModel(name: 'Salmon', number: 10, size: 'big'),
child: MaterialApp(
home: FishOrder(),
),
);
}
}
맨 아래 SpicyC로 이동해서 다음과 같이 ElevatedButton을 추가해준다. 여기서 context 옆에 listen:false 인자가 추가되었는데, 이를 추가해주지 않으면 ElevatedButton 자체도 changeFishNumber()를 적용하는 State management의 관리 대상이 되어 pointeless rebuild라는 에러가 뜬다. 불필요한 위젯 rebuild를 없애기 위해 listen: false를 적용하는 것이다.
//... 중략
SizedBox(
height: 20,
),
ElevatedButton(onPressed: () {
Provider.of<FishModel>(context, listen: false).changeFishNumber();
}
, child: Text('Change fish number'))
],
MultiProvider
Provider가 계층적으로 여러 개인 경우, 여러 번 ChangeNotifierProvider를 사용하면 가독성이 떨어질 수 있다. 한 번에 관리할 수 있게 해주는 것이 MultiProvider이다.
실습을 위해 SeaFishModel 클래스를 만든다.
import 'package:flutter/cupertino.dart';
class SeaFishModel with ChangeNotifier{
final String name;
int tunaNumber;
final String size;
SeaFishModel({required this.name, required this.tunaNumber, required this.size});
void changeSeaFishNumber() {
tunaNumber++;
notifyListeners();
}
}
그리고 ChangeNotifierProvider 부분을 아래처럼 변경해준다. MultiProvider는 리스트 형태로 Provider들을 인자로 받는다. 이제 해당 위젯은 FishModel, SeaFishModel의 2가지 데이터를 listen할 수 있게 되었다.
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) =>
FishModel(name: 'Salmon', number: 10, size: 'big'),
),
ChangeNotifierProvider(
create: (context) =>
SeaFishModel(name: 'Tuna', tunaNumber: 0, size: 'middle'),
)
],
child: MaterialApp(
home: FishOrder(),
),
);
}
SpicyB, Low 위젯 쪽에 아래처럼 ElevatedButton을 추가한다.
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(
'Tuna number: ${Provider.of<SeaFishModel>(context).tunaNumber}',
style: TextStyle(
fontSize: 16, color: Colors.red, fontWeight: FontWeight.bold),
),
Text(
'Fish size: ${Provider.of<FishModel>(context).size}',
style: TextStyle(
fontSize: 16, color: Colors.red, fontWeight: FontWeight.bold),
),
SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () {
Provider.of<SeaFishModel>(context, listen: false)
.changeSeaFishNumber();
},
child: Text('Sea fish Number')),
Low()
],
);
}
'Programming-[CrossPlatform] > Flutter' 카테고리의 다른 글
Flutter Provider: 4. GetX - Reactive State manager (0) | 2025.01.08 |
---|---|
Flutter Provider: 3. GetX - Simple State Manager (0) | 2025.01.06 |
Flutter Provider: 1. Provider와 State management (0) | 2025.01.01 |
[작성중][제철음식 알리미] bottomNavBar, didChangeDependencies, pageController (1) | 2024.10.22 |
[제철음식 알리미] ValueListenableBuilder, ValueNotifier (0) | 2024.10.21 |