728x90
반응형
우리가 배울 여러 상태 관리 방법을 이용해 데이터 일관성을 유지해 봅시다.
StatefulWidget
InheritedWidget
Provider(라이브러리)
Riverpod(라이브러리)
1단계 statelessWidget statefulWidget 위젯 만들어보기
StatelessWidget
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
debugShowCheckedModeBanner: false,
home: MyStatelessWidget(),
));
//statelessWidget은
//상태의 변화없이 항상 동일한 UI를 그린다.
//이런 위젯은 데이터나 변수의 값이 변하지 않을때 사용합니다.
//포인트!! => 사실 상태는 변수에 할당된 값을 말한다.
//stateless 위젯을 할때 그래서 상수값으로 많이 할당함 => final
class MyStatelessWidget extends StatelessWidget {
MyStatelessWidget({super.key});
final msg = '안녕하세요 저는 상태가 없는 (고정된) 메세지 잆니다.';
@override
Widget build(BuildContext context) {
return Center(
child: Text(msg),
);
}
}
StatefulWidget
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: MyStatefulWidget(),
));
}
//포인트! -> 사실 상태는 변수에 할당된 값이다.
//'상태가 있다' 라는 말은 값이 변화할 수 있는 가능성을 이야기한다.
//외부에서 보이는 부분
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({super.key});
//변수 --- 고정 ---> 상수
final msg = '저는 stateful 위젯입니다.';
//여기가 호출되고 => 아래의 private class를 보이게 된다.
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
//변수에 할당된 값이 상수가 아니기 때문에 언제든지 변경이 가능하다.
//즉 , 여기를 상태 변수라고 부른다.
int count = 0;
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Center(
child: InkWell(
onTap: () {
setState(() {
count += 1;
});
},
child: Text('${widget.msg} onTap Count : ${count}')),
),
));
}
}
- StatefulWidget
StatefulWidget은 상태를 변경할 수 있고, 상태가 변경된 경우 setState()를 호출하여 자식 위젯들을 갱신할 수 있습니다.
2 단계 도서관리 앱으로 상태변화 관리해보기
도서 관리 앱 - 위젯 트리 구조 (StatefulWidget을 이용한 상태 관리)
homePage (StatefulWidget)
| ├── 공유 상태: 대출 목록에 추가된 도서 목록 (공유 상태)
|
├── Library (Store 역할)
| ├── Book 1 (도서 목록)
| ├── Book 2
| ├── Book 3
| └── Book 4
|
└── BorrowList (Cart 역할)
├── Book 2 (대출 목록에 추가된 책)
└── Book 4
기본 구성하기
main 화면
import 'package:flutter/material.dart';
import 'home_screen.dart';
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
//flutter에서 material3 적용
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), // 색상을 알아서 조합해줌
),
home: HomeScreen(),
));
}
home_screen.dart
import 'package:flutter/material.dart';
import '../common.utils/logger.dart';
import 'book_cart_page.dart';
import 'book_list_page.dart';
class HomeScreen extends StatefulWidget {
HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
//로컬상태
int pageIndex = 0;
// 공유상태 => 여러 위젯에서 관리할 수 있음 => 카트에 담긴 책 정보( 책 리스트 화면과, 장바구니 화면에서 공유하는 데이터)
// 상품 -> 책 (String) 타입으로 관리하자
//객체 배열로 관리할 수 있다.
List<String> mySelectedBook = [];
//상태를 변경하는 메서드 만들기
void _toggleSaveStates(String book) {
//다시 화면을 그려라 => 요청함수
setState(() {
if (mySelectedBook.contains(book)) {
mySelectedBook.remove(book);
} else {
mySelectedBook.add(book);
}
});
}
@override
void initState() {
// TODO: implement initState
super.initState();
setState(() {
pageIndex = 0;
});
}
void _changePageIndex(int index) {
setState(() {
pageIndex = index;
});
}
@override
Widget build(BuildContext context) {
logger.d('HomeScreen build 메서드 호출됨 ');
return SafeArea(
child: Scaffold(
appBar: AppBar(
leading: IconButton(
onPressed: () {},
icon: Icon(
Icons.arrow_back_ios,
color: Colors.white,
),
),
title: Text(
'지니의 서재',
style: TextStyle(color: Colors.white),
),
actions: [
Icon(
Icons.shopping_cart,
color: Colors.white,
)
],
backgroundColor: Theme.of(context).colorScheme.onSurfaceVariant,
),
body: IndexedStack(
index: pageIndex,
children: [
BookListPage(),
BookCartPage(),
],
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: pageIndex,
onTap: (index) => _changePageIndex(index),
items: [
BottomNavigationBarItem(icon: Icon(Icons.list), label: 'book-list'),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_cart), label: 'book-cart'),
],
),
));
}
}
book_list_page.dart book_cart_page
import 'package:flutter/material.dart';
class BookListPage extends StatelessWidget {
const BookListPage({super.key});
@override
Widget build(BuildContext context) {
return Center(
child: Text('북 리스트 페이지'),
);
}
}
import 'package:flutter/material.dart';
class BookCartPage extends StatelessWidget {
const BookCartPage({super.key});
@override
Widget build(BuildContext context) {
return Center(
child: Text('Book cart page'),
);
}
}
Call back 사용해보기
home_screen
=> home screen에서 선언된 함수와 list 를 하위에 전달하기
import 'package:flutter/material.dart';
import '../common.utils/logger.dart';
import 'book_cart_page.dart';
import 'book_list_page.dart';
class HomeScreen extends StatefulWidget {
HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
//로컬상태
int pageIndex = 0;
// 공유상태 => 여러 위젯에서 관리할 수 있음 => 카트에 담긴 책 정보( 책 리스트 화면과, 장바구니 화면에서 공유하는 데이터)
// 상품 -> 책 (String) 타입으로 관리하자
//객체 배열로 관리할 수 있다.
List<String> mySelectedBook = [];
//상태를 변경하는 메서드 만들기
void _toggleSaveStates(String book) {
//다시 화면을 그려라 => 요청함수
setState(() {
if (mySelectedBook.contains(book)) {
mySelectedBook.remove(book);
} else {
mySelectedBook.add(book);
}
});
}
@override
void initState() {
// TODO: implement initState
super.initState();
setState(() {
pageIndex = 0;
});
}
void _changePageIndex(int index) {
setState(() {
pageIndex = index;
});
}
@override
Widget build(BuildContext context) {
logger.d('HomeScreen build 메서드 호출됨 ');
return SafeArea(
child: Scaffold(
appBar: AppBar(
leading: IconButton(
onPressed: () {},
icon: Icon(
Icons.arrow_back_ios,
color: Colors.white,
),
),
title: Text(
'지니의 서재',
style: TextStyle(color: Colors.white),
),
actions: [
Icon(
Icons.shopping_cart,
color: Colors.white,
)
],
backgroundColor: Theme.of(context).colorScheme.onSurfaceVariant,
),
body: IndexedStack(
index: pageIndex,
children: [
BookListPage(
mySelectedBooked: mySelectedBook,
onToggleSaved: _toggleSaveStates,
),
BookCartPage(
mySelectedBooked: mySelectedBook,
onToggleSaved: _toggleSaveStates,
),
],
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: pageIndex,
onTap: (index) => _changePageIndex(index),
items: [
BottomNavigationBarItem(icon: Icon(Icons.list), label: 'book-list'),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_cart), label: 'book-cart'),
],
),
));
}
}
book_list_page
전달받은 내용 사용하여 코드 구현하기
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../common.utils/logger.dart';
class BookListPage extends StatelessWidget {
final Function(String) onToggleSaved;
final List<String> mySelectedBooked;
BookListPage(
{required this.onToggleSaved, required this.mySelectedBooked, super.key});
//임시데이터 - 교보문고에 볼 수 있는 책 목록 리스트
final List<String> books = [
'호모사피엔스',
'dart입문',
'홍길동전',
'code Refactoring',
'전치사도감',
];
@override
Widget build(BuildContext context) {
logger.d('데이터 확인 : ${mySelectedBooked.toString()}');
return SafeArea(
child: Scaffold(
body: ListView(
children: books.map(
(book) {
//함수의 body에는 식을 작성할 수 있다
final isSelecedBook = mySelectedBooked.contains(book);
//부모가 관리하는 장바구니 데이터에 있는지 없는지
return ListTile(
leading: Container(
width: 35,
height: 35,
decoration: BoxDecoration(
color: Theme.of(context).secondaryHeaderColor,
borderRadius: BorderRadius.circular(8.0),
border: Border.all(color: Theme.of(context).primaryColor),
),
),
title: Text(
book,
style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
),
trailing: IconButton(
onPressed: () {
onToggleSaved(book);
},
icon: isSelecedBook
? Icon(Icons.remove_circle)
: Icon(Icons.add_circle),
color: isSelecedBook ? Colors.red : Colors.green,
),
);
},
).toList(),
),
),
);
}
}
book_cart_page
import 'package:flutter/material.dart';
class BookCartPage extends StatelessWidget {
final Function(String) onToggleSaved;
final List<String> mySelectedBooked;
const BookCartPage(
{required this.onToggleSaved, required this.mySelectedBooked, super.key});
@override
Widget build(BuildContext context) {
return ListView(
children: mySelectedBooked.map((cart) {
return ListTile(
leading: Container(
width: 35,
height: 35,
decoration: BoxDecoration(
color: Theme.of(context).secondaryHeaderColor,
borderRadius: BorderRadius.circular(8.0),
border: Border.all(color: Theme.of(context).primaryColor),
),
),
title: Text(
cart,
style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
),
trailing: IconButton(
onPressed: () {
onToggleSaved(cart);
},
icon: Icon(
Icons.remove_circle,
color: Theme.of(context).primaryColor,
)),
);
}).toList());
}
}
728x90
반응형
'Flutter' 카테고리의 다른 글
[flutter] 상태관리가 되는 앱 만들어 보기 02 (inheritedWidget) (0) | 2025.01.20 |
---|---|
[flutter] 로컬 상태와 공유 상태 (0) | 2025.01.20 |
[flutter] StatelessWidget 과 StatefulWidget (0) | 2025.01.20 |
댓글