Flutter에서 Key는 위젯, 요소(Element), 그리고 시맨틱 노드(Semantic Node)를 식별하는 데 사용되는 고유 식별자이다. Key는 위젯 트리가 재구성될 때 기존 상태와 연결 관계를 유지하는 데 중요한 역할을 한다. 이번 블로그에서는 Key의 개념, 사용 시점, 작동 원리, 그리고 다양한 Key 유형에 대해 정리해보도록 한다.
Key란 무엇인가?
- Key의 역할: Key는 위젯이 트리에서 이동할 때 상태를 유지하도록 돕는다. 동일한 부모 아래에 있는 위젯들 간에 고유해야 하며, Key가 동일한 경우에만 기존 요소(Element)가 업데이트된다.
- 필요성: 동일한 유형의 여러 위젯이 있는 경우, Flutter는 어떤 위젯이 어떤 데이터와 상태를 가지는지 구분할 수 있어야 하는데, 이 때 Key가 이를 도와준다.
Key를 사용하는 시점
Key는 다음과 같은 상황에서 주로 사용된다.
- 동일한 유형의 여러 위젯이 있을 때:
예: 리스트(ListView)나 상태(Stateful) 위젯처럼 데이터가 자주 변경되거나 순서가 바뀌는 경우 - 위젯 상태를 재구성 중에도 유지해야 할 때:
예: 항목 순서를 변경하거나 특정 데이터를 유지해야 하는 To-Do 리스트 - Stateless 위젯만 있는 경우에는 Key가 필요하지 않다. (단, Stateless 위젯만 사용하더라도 동일한 유형의 위젯이 중복되거나 순서가 변경되는 경우에는 Key가 필요할 수 있다.)
다음은 재정렬이 가능한 리스트를 코드로 구현하면서 자세히 알아보도록 한다.
Key 없이 구현한 경우,
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Reorderable List Example')),
body: ReorderableList(),
),
);
}
}
class ReorderableList extends StatefulWidget {
@override
_ReorderableListState createState() => _ReorderableListState();
}
class _ReorderableListState extends State<ReorderableList> {
List<String> items = ['Item 1', 'Item 2', 'Item 3'];
@override
Widget build(BuildContext context) {
return ReorderableListView(
onReorder: (oldIndex, newIndex) {
if (newIndex > oldIndex) {
newIndex -= 1;
}
setState(() {
final item = items.removeAt(oldIndex);
items.insert(newIndex, item);
});
},
children: items.map((item) {
return ListTile(
title: Text(item),
);
}).toList(),
);
}
}
위 코드에서는 Key가 없으면 Flutter는 각 항목을 고유하게 식별할 수 없기 때문에 결과적으로 재정렬 중 일부 항목의 상태가 손실되거나 UI가 제대로 업데이트되지 않을 수 있다. 이번에는 Key를 추가해보자.
Key를 추가한 경우, (ValueKey 추가)
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Reorderable List Example')),
body: ReorderableList(),
),
);
}
}
class ReorderableList extends StatefulWidget {
@override
_ReorderableListState createState() => _ReorderableListState();
}
class _ReorderableListState extends State<ReorderableList> {
List<String> items = ['Item 1', 'Item 2', 'Item 3'];
@override
Widget build(BuildContext context) {
return ReorderableListView(
onReorder: (oldIndex, newIndex) {
if (newIndex > oldIndex) {
newIndex -= 1;
}
setState(() {
final item = items.removeAt(oldIndex);
items.insert(newIndex, item);
});
},
children: items.map((item) {
return ListTile(
key: ValueKey(item),
title: Text(item),
);
}).toList(),
);
}
}
ValueKey를 사용하여 각 항목을 고유하게 식별하게 처리했기 때문에 Flutter가 항목을 올바르게 추적하고 상태를 유지할 수 있다.
※ ReorderableListView 사용에 대하여...
Flutter 3.7 이상에서는 children 대신 buildDefaultDragHandles 옵션을 활용하여 리스트 항목의 드래그 핸들을 조정할 수 있다.
Flutter에서 Key의 작동 원리
Flutter는 두 가지 주요 트리를 유지한다.
- Element Tree (실행 중인 앱의 상태를 나타냄)
- Widget Tree (UI 구조를 정의)
- 위젯이 재구성될 때, Flutter는 새 위젯과 기존 위젯을 비교하여 일치 여부를 확인한다.
- 일치 기준:
· 동일한 부모 아래에서 생성됨
· 동일한 유형과 Key를 가짐
- 일치하면 기존 요소를 업데이트하고 그렇지 않으면 새로 생성한다.
Key의 종류
- ValueKey:
- 특정 값 (예: 문자열)을 기준으로 고유하게 식별
- To-Do 리스트의 텍스트 값 등이 있다. - ObjectKey:
- 객체(Object)를 기준으로 식별
- 객체가 두 개 이상의 필드로 구성된 경우 유용 - UniqueKey:
- 고유 값이 없거나 모든 항목을 새로 빌드해야 할 때 사용
- 항상 새로운 키를 생성함 - GlobalKey:
- 앱 전체에서 고유하며, 다른 위젯의 상태에 접근하거나 조작할 때 사용
- 특정 위젯의 상태를 외부에서 관리해야 할 때 유용
결론
Flutter에서 Key는 UI 상태 관리와 성능 최적화에 중요한 역할을 한다. 특히 데이터 순서가 변경되거나 상태를 유지해야 하는 상황에서 필수적이며, 다양한 유형의 Key(ValueKey, ObjectKey 등)를 적절히 활용하면 복잡한 UI에서도 안정적이고 효율적인 동작을 보장할 수 있다.
아래 링크의 포스팅을 참고하여 정리한 내용입니다. 원문을 확인하고 싶으시면 아래 링크를 확인해주세요.
출처 - https://blog.nonstopio.com/understanding-the-power-of-keys-in-flutter-389ba0abdf1d
'Personal Posting > Flutter' 카테고리의 다른 글
Dart 프로그래밍에서의 애노테이션(Annotations) (0) | 2025.01.07 |
---|---|
Flutter MVVM 구조 (Officially recommended by Google) (0) | 2025.01.06 |
Flutter에서의 메모리릭 (0) | 2025.01.06 |
Flutter 스피드 다이얼 구현 (0) | 2025.01.06 |
Flutter 웹 로딩 속도 최적화 (0) | 2025.01.06 |