본문 바로가기

Flutter

플러터 기본기 다지기 - 4 (Flutter의 위젯과 Element 트리 그리고 Key)

Flutter의 위젯과 Element 트리 그리고 Key의 역할과 사용 방법

  • Flutter는 각 위젯마다 Element 객체를 생성해 트리 구조를 만든다.
  • Element는 위젯의 타입, 위치 정보를 저장하고 자식 Element와 연결되어 전체 트리를 구성한다.

 

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(home: MyHomePage()));
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final listTile = <Tile>[
    Tile(color: Colors.blue, name: '파란색 타일'),
    Tile(color: Colors.red, name: '빨간색 타일'),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('키가 없는 위젯을 만들어 보기'),
      ),
      body: Center(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: listTile,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: swapTiles,
        child: Icon(Icons.swap_horiz),
      ),
    );
  } // end of build()

// 첫번째 타일과 두번째 타일을 교환 하는 기능
void swapTiles() {
    // ['파란색타일', '빨간색타일']
    setState(() {
      // 첫 번째 타일을 제거하고 그 타일을 반환하는 기능
      // [ '빨간색타일']
      // var removedTile = listTile.removeAt(0);
      // [ '빨간색타일', '파란색타일']
      // 제거된 타잉르 두 번째 위치로 삽입하자.
      // listTile.insert(1, removedTile);

      // 축약해서 코드 작성
      listTile.insert(1, listTile.removeAt(0));
    });
}


} // end of state class

class Tile extends StatefulWidget {
  final Color color; // 타일에 색상
  final String name; // 타일에 이름

  const Tile({required this.color, required this.name});

  @override
  State<Tile> createState() => _TileState();
}

// 커스텀 Tile 클래스의 상태 관리 클래스 입니다.
class _TileState extends State<Tile> {
  // State 멤버 변수 widget 이런 멤버 변수를 제공해서 상위 클래스이 접근 할 수
  // 있도록 만들어 주고 있다.
  Color? currentColor; // 현재 타일에 색상을 지정

  @override
  void initState() {
    super.initState();
    // 부모 클래스 변수에 접근에서 값을 가져 옴
    currentColor = widget.color;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: currentColor,
      width: 100,
      height: 100,
      alignment: Alignment.center,
      child: Text(
        widget.name,
        style: const TextStyle(
          color: Colors.white,
          fontWeight: FontWeight.bold,
        ),
      ),
    );
  }
}

State 클래스는 StatefulWidget과 연결된 상태 관리 클래스로, Flutter에서 위젯의 상태를 저장하고 변경하는 역할을 담당한다. State 클래스는 부모 Widget에 연결된 속성이나 값에 직접 접근할 수 없기 때문에, widget 객체를 통해 부모 Widget의 속성 값을 사용할 수 있다.

Flutter는 위젯 트리에서 동일한 타입의 위젯을 재사용한다. 위젯의 순서가 바뀌거나 새로 추가되는 경우, 이전 상태를 그대로 이어가게 되어 UI 버그가 발생할 수 있다. 예를 들어, 리스트에서 순서를 바꾸면 Flutter는 기존의 상태를 재사용하여 버그가 발생할 수 있다.

 

 

💡 Key를 사용하지 않아 위젯을 교환할 때 상태가 제대로 업데이트되지 않음

 

 

Flutter에서 Key의 역할과 필요성

Key는 Flutter 애플리케이션에서 위젯의 고유성을 보장하고, 상태를 관리하는 데 중요한 역할을 한다. 특히, 위젯 트리에서 요소의 순서가 변경되거나 목록이 동적으로 업데이트될 때 Key는 의도하지 않은 UI 동작을 방지하는 핵심 요소이다.

 

 

Key란 무엇인가?

  • Flutter는 모든 위젯마다 Element라는 객체를 내부적으로 생성해 트리를 만든다.
  • Flutter에서 Key는 각 위젯을 고유하게 식별하기 위한 속성이다.
  • 복잡한 위젯 트리 구조에서 위치가 바뀌거나, 재구성될 때 위젯을 정확히 식별하는 데 중요한 역할을 한다.

 

Key의 작동 방식

Flutter는 Key를 통해 위젯을 고유하게 식별한다. 같은 타입이라도 Key가 다르면 Flutter는 이를 별개의 위젯으로 인식하고, 다른 상태를 유지하도록 처리힌다. 따라서 Key가 있는 위젯의 순서가 변경되면 Flutter는 새로운 위치에 있는 위젯의 상태를 유지하도록 관리한다.

 

 

Key 를 활용한 UI 버그를 방지하는 방법 확인
import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(home: MyHomePage()));
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final listTile = <Tile>[
    Tile(key: ValueKey('파란색'), color: Colors.blue, name: '파란색 타일'),
    Tile(key: ValueKey('빨간색'),  color: Colors.red, name: '빨간색 타일'),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('키가 없는 위젯을 만들어 보기'),
      ),
      body: Center(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: listTile,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: swapTiles,
        child: Icon(Icons.swap_horiz),
      ),
    );
  } // end of build()

// 첫번째 타일과 두번째 타일을 교환 하는 기능
void swapTiles() {
    // ['파란색타일', '빨간색타일']
    setState(() {
      // 첫 번째 타일을 제거하고 그 타일을 반환하는 기능
      // [ '빨간색타일']
      // var removedTile = listTile.removeAt(0);
      // [ '빨간색타일', '파란색타일']
      // 제거된 타잉르 두 번째 위치로 삽입하자.
      // listTile.insert(1, removedTile);

      // 축약해서 코드 작성
      listTile.insert(1, listTile.removeAt(0));
    });
}


} // end of state class

class Tile extends StatefulWidget {
  final Color color; // 타일에 색상
  final String name; // 타일에 이름

  //Key 속성을 추가해서 부모클래스 (Sate)고유 식별자를 보장한다.
  const Tile({required Key key,
    required this.color, required this.name}) : super(key: key);

  @override
  State<Tile> createState() => _TileState();
}

// 커스텀 Tile 클래스의 상태 관리 클래스 입니다.
class _TileState extends State<Tile> {
  // State 멤버 변수 widget 이런 멤버 변수를 제공해서 상위 클래스이 접근 할 수
  // 있도록 만들어 주고 있다.
  Color? currentColor; // 현재 타일에 색상을 지정

  @override
  void initState() {
    super.initState();
    // 부모 클래스 변수에 접근에서 값을 가져 옴
    currentColor = widget.color;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: currentColor,
      width: 100,
      height: 100,
      alignment: Alignment.center,
      child: Text(
        widget.name,
        style: const TextStyle(
          color: Colors.white,
          fontWeight: FontWeight.bold,
        ),
      ),
    );
  }
}

 

 

💡 핵심 정리


Key의 기본 이해:
Key는 위젯 트리에서 각 위젯의 고유성을 보장하여 Flutter가 상태를 일관되게 관리하도록 도와준다. Key는 특히 위젯의 순서가 바뀌거나 새롭게 추가될 때 중요한 역할을 한다.

Key를 사용하지 않을 때 발생하는 문제:
Flutter는 동일한 타입의 위젯을 재사용하기 때문에, 순서 변경이나 상태 관리에 버그가 발생할 수 있다. Key가 없을 경우 Flutter는 어떤 위젯이 기존의 것인지 새로 생성된 것인지 구별하지 못할 수 있다.

UI 버그 해결:
리스트나 Row, Column과 같은 여러 위젯이 반복되는 레이아웃에서 Key를 사용하면 Flutter는 각 위젯을 고유하게 인식할 수 있으며, 이를 통해 UI가 의도치 않게 변경되는 것을 방지할 수 있다.

Key의 종류와 사용 방법:
ValueKey와 같은 고유한 값 기반의 Key, UniqueKey와 같이 무작위로 생성되는 Key등이 있습니다 각각의 Key는 특정 시나리오에서 유용하게 사용되며, 상태를 안전하게 유지하면서 UI 버그를 방지하는 데 도움이 된다.

728x90

'Flutter' 카테고리의 다른 글

당근 마켓 만들어 보기  (2) 2024.11.19
MVVM 패턴과 상태 관리  (0) 2024.11.15
플러터 기본기 다지기 - 4 (GestureDetector 위젯)  (0) 2024.11.14
Dio 통신 연습  (0) 2024.11.14
플러터 기본기 다지기 - 3 (TabBar 위젯)  (1) 2024.11.14