Flutter의 Dialog 안에서 setState 하기
오늘은 Flutter 개발 중에 꽤나 골치 아팠던 문제, 바로 **Dialog 안에서 setState를 사용하는 방법**에 대해 속 시원하게 알려드리려고 합니다. 저도 처음에 이 문제 때문에 몇 시간이고 끙끙댔던 기억이 나네요 😅 하지만 이제 걱정 끝! 이 글을 읽고 나면 Dialog 안에서 데이터 변경을 깔끔하게 처리할 수 있을 거예요.
**문제 상황: 왜 Dialog 안에서 setState가 안될까요?**
대부분의 Flutter 개발자들은 화면 업데이트를 위해 `setState`를 사용하는데 익숙하죠. 하지만 Dialog 안에서는 `setState`를 사용해도 화면이 갱신되지 않는 답답한 상황에 직면하게 됩니다. 왜 그럴까요? 간단히 말해, `setState`는 **해당 위젯 트리**를 재빌드하는 역할을 하기 때문입니다. Dialog는 메인 화면의 위젯 트리와는 별개의 트리를 가지고 있어서, Dialog 안에서 `setState`를 호출해도 메인 화면의 `setState`만 호출되는 겁니다.
**해결 방법: StatefulBuilder를 활용하세요! ✨**
자, 이제 해결책을 알려드릴게요! 바로 `StatefulBuilder` 위젯을 사용하는 겁니다. `StatefulBuilder`는 자신만의 독립적인 상태를 관리하고, 내부에서 `StateSetter`를 이용해 UI를 업데이트할 수 있도록 해줍니다. 말로만 설명하면 어려우니, 바로 코드로 보여드릴게요!
**1. 프로젝트 구조**
먼저 프로젝트를 다음과 같이 구성해 봅시다. 간단하게 `main.dart`, `alter_dialog.dart`, `basic_button.dart` 세 개의 파일로 구성했습니다.
**2. main.dart**
```dart
import 'package:flutter/material.dart';
import 'alter_dialog.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const DialogSetState(),
);
}
}
class DialogSetState extends StatefulWidget {
const DialogSetState({super.key});
@override
State<DialogSetState> createState() => _DialogSetStateState();
}
class _DialogSetStateState extends State<DialogSetState> {
int goalCount = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Dialog SetState Example'),
),
body: Center(
child: ElevatedButton(
onPressed: () => alterDialogSetState(
goalCount: goalCount,
context: context,
closePressed: () {
setState(() {
// Dialog 닫을 때 메인 화면의 상태 업데이트 (필요에 따라 추가)
Navigator.pop(context);
});
},
),
child: const Text('Show Dialog'),
),
),
);
}
}
```
**3. alter_dialog.dart (핵심!)**
```dart
import 'package:flutter/material.dart';
// 재사용 가능한 버튼 위젯
Widget basicTextButton({required String buttonText, required VoidCallback onPressed}) {
return TextButton(
onPressed: onPressed,
child: Text(buttonText, style: const TextStyle(fontSize: 15)),
);
}
alterDialogSetState({
required BuildContext context,
required Function() closePressed,
required int goalCount,
}) {
showDialog(
context: context,
builder: (context) => StatefulBuilder( // StatefulBuilder 사용!
builder: (BuildContext context, StateSetter setDialog) { // StateSetter 받아오기
return AlertDialog(
title: const Text('Goal Counter'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image.asset(
'assets/son.png', // 이미지 경로 설정
width: 120,
height: 100,
),
basicTextButton(
buttonText: 'Goal!',
onPressed: () {
setDialog(() { // StateSetter 사용하여 상태 업데이트
goalCount++;
});
},
),
Text('Goal Count: $goalCount'),
],
),
actions: [
basicTextButton(buttonText: 'Close', onPressed: closePressed),
],
);
},
),
);
}
```
**4. assets/son.png**
`pubspec.yaml` 파일에 assets를 추가하고, assets 폴더에 적절한 이미지를 추가하세요. 예를 들어, 축구 선수 사진을 사용할 수 있습니다.
```yaml
flutter:
assets:
- assets/son.png
```
**핵심 코드 설명:**
* `StatefulBuilder`: Dialog의 내부 상태를 독립적으로 관리합니다.
* `StateSetter setDialog`: `StatefulBuilder`에서 제공하는 함수로, Dialog 내부의 상태를 변경하고 UI를 업데이트합니다. `setDialog(() { ... });` 안에서 상태 변경 로직을 작성하면 됩니다.
**실행 결과 GIF**
(여기에 실행 결과 GIF를 삽입하세요. 위에 제공된 GIF 링크를 사용하거나, 직접 실행하여 GIF를 생성하여 삽입하면 됩니다.)
**결론:**
`StatefulBuilder`와 `StateSetter`를 사용하면 Dialog 안에서도 깔끔하게 데이터를 업데이트하고 화면을 갱신할 수 있습니다. 이제 Dialog 안에서 setState 때문에 고민할 필요가 없겠죠?
'Tech Story' 카테고리의 다른 글
[Python] Dictionary 와 JSon 비교 및 변환 (1) | 2025.05.31 |
---|---|
[SQL] SQL vs No-SQL (1) | 2025.05.31 |
[Flutter] RestfulAPI 호출 방법 (Debugging & Release Mode) (0) | 2025.05.31 |
[Docker / NginX] Docker 와 NginX (0) | 2025.05.31 |
[Docker / NginX] 하나의 Domain을 Multi Site로 운영 (0) | 2025.05.31 |