[Flutter] Stateful 위젯

류재성's avatar
Apr 16, 2024
[Flutter] Stateful 위젯
 

1. Stateful 위젯

💡
Stateful 위젯은 변경 가능한 상태를 가진 위젯을 의미한다. 위젯이 처음 화면에 그려질 때 변수의 값(상태값)에 따라 위젯을 그릴 수 있고, 화면에 그림이 그려진 후 사용자의 액션에 따라 위젯을 다시 그릴 수도 있는 위젯이다.
 
  • 변경 가능한 상태를 가지고 있다.
  • 위젯의 상태와 모양을 분리하여 관리한다.
  • setState() 함수를 사용하여 상태 변경을 알리고 위젯을 다시 그린다.
  • 위젯이 빌드될 때마다 상태를 읽을 수 있다.
 

2. Statefull 기본

 
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: HomePage(), ); } } class HomePage extends StatefulWidget { @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { int num = 1; @override Widget build(BuildContext context) { print("그림 그려짐"); return Container( color: Colors.yellow, child: Padding( padding: const EdgeInsets.all(20.0), child: Column( children: [ Text("${num}"), TextButton( onPressed: () { num ++; print("num : ${num}"); setState(() {}); // 리빌드 }, child: Text("증가")), ], ), ), ); } }
 
💡
HomePage는 stateful 위젯을 가진다. 증가 버튼이 눌려질 때 마다 숫자가 증가한다.
 
notion image
 
notion image
notion image
 
 

3. BuildContext 분리하기

 
notion image
 
💡
BuildContext는 위젯 트리에서 현재 위젯의 위치를 나타내는 핸들이다. 모든 위젯은 자신의 BuildContext를 가지고 있으며, 이는 위젯의 부모 위젯에 대한 참조이다.
notion image
 
💡
컴포넌트를 HeaderPage와 BottomPage를 만들었다. 컴포넌트를 분리하면 두 컴포넌트가 공유하는 최단의 부모 위젯를 stateful 상태로 만들어야 한다.
 
 
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: HomePage(), ); } } class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { int num = 1; void increase() { num++; setState(() {}); } @override Widget build(BuildContext context) { return Container( color: Colors.yellow, child: Padding( padding: const EdgeInsets.all(20), child: Column( children: [ Expanded(child: HeaderPage(num)), Expanded(child: BottomPage(increase)), ], ), ), ); } } class HeaderPage extends StatelessWidget { int num; HeaderPage(this.num); @override Widget build(BuildContext context) { print("header"); return Container( color: Colors.red, child: Align( child: Text( "${num}", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 100, decoration: TextDecoration.none), ), ), ); } } class BottomPage extends StatelessWidget { Function increase; BottomPage(this.increase); @override Widget build(BuildContext context) { print("bottom"); return Container( color: Colors.blue, child: Align( child: ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: Colors.red), onPressed: () { print("버튼 클릭됨"); increase(); }, child: Text( "증가", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 100, ), ), ), ), ); } }
 
notion image
 
💡
부모인 HomePage 클래스가 HeaderPage와 BottomPage 에 각각 변수 num 과 함수 increase 를 전달한다. 증가 버튼을 누르면 페이지 전체가 리로드 되면서 숫자가 증가된다.
 
 

4. 그렇다면 왜 컴포넌트를 나누는 것일까?

 
 
notion image
 
💡
현재의 그림은 이런 그림이다. 부모의 페이지 전체를 리로드 한다면 굳이 버튼 위젯과 숫자 위젯을 나눌 필요가 없다.
 
 
 
 
 
notion image
 
💡
이런 구조를 가진다면? 하나를 리로드 하기 위해 모든 페이지가 새롭게 그려져야 한다. 그렇기 때문에 부모 위젯을 stateful 로 한다 하더라도, 전체 구조에선 일부분이기 때문에 컴포넌트를 분리해야 효율적이다.
Share article

{CODE-RYU};