안녕하세요. 지난 글에서는 플러터(flutter)에서 메모장 앱을 만들기 위해 List for문 사용하여 데이터를 보여주고 Add(추가), remove(삭제) 메서드를 사용하는 데이터를 삭제, 추가해보았습니다. 이번 글에서는 플러터 상태관리 기능을 통해 데이터의 상황을 화면에 업데이트하기 위한 방법에 대해 작성하겠습니다.
목차
플러터 상태관리
지난 코드에서는 상태 관리가 없었기 때문에 items 리스트를 변경할 때마다 화면이 업데이트되지 않았습니다. 플러터에서는 상태를 관리하는 방법이 여러 가지 있으며 이를 통해 상태가 변경될 때마다 화면을 다시 그릴 수 있습니다. 코드 전체를 살펴보겠습니다.
메인함수
동일하게 메인함수에 runApp()을 사용하여 MyMemoApp() 루트 위젯을 실행합니다.
import 'package:flutter/material.dart'; void main() { runApp(MyMemoApp()); }
StatelessWidget
메모 앱의 진입점은 정적이므로 StatelessWidget을 상속합니다. MaterialApp home 속성으로 MyMemoAppPage() 클래스를 가져옵니다.
// MyMemoApp 클래스: StatelessWidget을 상속하는 메모 앱의 진입점 class MyMemoApp extends StatelessWidget { @override Widget build(BuildContext context) { // MaterialApp을 반환 return MaterialApp( home: MyMemoAppPage(), // 홈 페이지로 MyMemoAppPage 사용 ); } }
StatefulWidget
메모 앱의 페이지는 삭제, 추가의 업데이트 과정을 보여주기 위한 상태 관리가 필요하기 때문에 StatefulWidget을 상속합니다. createState 메서드는 StatefulWidget이 생성될 때 호출되는 메서드 입니다. _MyMemoAppPageState을 반환하여 상태를 보여줍니다. (상태 변화가 필요할때 _MyMemoAppPageState가 매번 수행된다고 이해하면 될 것 같습니다.)
// MyMemoAppPage 클래스: StatefulWidget을 상속하는 메모 앱의 홈 페이지 class MyMemoAppPage extends StatefulWidget { @override State<MyMemoAppPage> createState() => _MyMemoAppPageState(); // 상태를 관리하는 State를 생성하는 메서드 }
setState() 메서드 사용
메모장 UI을 동적으로 업데이트하기 위해서는 StatefulWidget에서 setState()를 사용해야 됩니다. 기존 코드에서 동작이 일어나는 추가, 삭제 버튼의 onPressed 속성에 아래와 같은 형식으로 추가해 줍니다.
// 메모 추가 버튼
IconButton(
onPressed: () {
setState(() {
items.add('New Item'); // 새로운 아이템 추가
print(items);
});
},
style: IconButton.styleFrom(foregroundColor: Colors.white),
icon: Icon(Icons.create),
),
appbar의 오른쪽 상단 버튼을 클릭하여 New Item을 추가한 것을 확인할 수 있습니다.
// 아이템 삭제 버튼
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
setState(() {
items.removeAt(index); // 아이템 삭제
print(items);
});
},
),
리스트뷰의 오른쪽 삭제 버튼을 클릭하여 해당 메모를 삭제하였습니다.
setState()을 사용한 코드입니다.
// _MyMemoAppState 클래스: _MyMemoApp의 상태를 관리하는 State 클래스 class _MyMemoAppPageState extends State<MyMemoAppPage> { List<String> items = ['Item 0', 'Item 1', 'Item 2']; // 메모 아이템 목록 @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Memo', style: TextStyle(color: Colors.white)), backgroundColor: Colors.black, actions: [ // 메모 추가 버튼 IconButton( onPressed: () { setState(() { items.add('New Item'); // 새로운 아이템 추가 print(items); }); }, style: IconButton.styleFrom(foregroundColor: Colors.white), icon: Icon(Icons.create), ), ], ), body: ListView.builder( itemCount: items.length, itemBuilder: (context, index) { // 각 메모 아이템을 나타내는 ListTile return ListTile( title: Text(items[index]), trailing: IconButton( icon: const Icon(Icons.delete), onPressed: () { setState(() { items.removeAt(index); // 아이템 삭제 print(items); }); }, ), ); }, ), ); } }
setState() 단점
widget build가 시작되는 부분에 print(‘build’);을 넣어서 과정을 확인해 보면 setState() 메서드가 실행될 때 매번 출력되는 것을 확인할 수 있습니다. 즉 _MyMemoAppPageState() 클래스가 매번 실행하면서 업데이트됩니다.
... class _MyMemoAppPageState extends State<MyMemoAppPage> { List<String> items = ['Item 0', 'Item 1', 'Item 2']; // 메모 아이템 목록 @override Widget build(BuildContext context) { print('build'); ...
앱에서 상태를 업데이트하고 UI를 다시 그리는데 상태관리가 필요하지만 setState()에는 단점이 있습니다.
- 성능 : 위젯 전체를 다시 렌더링하기때문에 성능 저하를 일으킬 수 있습니다.
- 비동기적 업데이트 : 비동기적으로 동작하므로 즉시 상태 업데이트되지 않을 수 있습니다. 이로 인해 예상치 못한 상태 변화가 발생할 수 있습니다.
- 복잡성 : 상태가 여러 곳에서 관리되고 업데이트되는 경우, 코드의 복잡해집니다.
- 코드 가독성 : 큰 프로젝트에서 사용될 경우 코드 가독성이 감소할 수 있습니다.
마무리
지금까지 StatefulWidget의 setState()를 이용하여 상태 관리를 하는 방법에 대해 알아보았습니다. 플러터(flutter) 앱에서 상태를 업데이트하고 UI를 다시 그리는데 상태 관리가 필요하지만 setState()에는 여러 단점이 있었습니다. 이를 보완하기 위한 여러가지 방법이 있지만 일단 다음 글에서는 메모를 입력하는 새로운 페이지를 만들고 커스텀 위젯에 대해서 알아보겠습니다. 읽어주셔서 감사합니다.