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 위젯을 가진다. 증가 버튼이 눌려질 때 마다 숫자가 증가한다.
3. BuildContext 분리하기
BuildContext는 위젯 트리에서 현재 위젯의 위치를 나타내는 핸들이다. 모든 위젯은 자신의 BuildContext를 가지고 있으며, 이는 위젯의 부모 위젯에 대한 참조이다.
컴포넌트를 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, ), ), ), ), ); } }
부모인 HomePage 클래스가 HeaderPage와 BottomPage 에 각각 변수 num 과 함수 increase 를 전달한다. 증가 버튼을 누르면 페이지 전체가 리로드 되면서 숫자가 증가된다.
4. 그렇다면 왜 컴포넌트를 나누는 것일까?
현재의 그림은 이런 그림이다. 부모의 페이지 전체를 리로드 한다면 굳이 버튼 위젯과 숫자 위젯을 나눌 필요가 없다.
이런 구조를 가진다면? 하나를 리로드 하기 위해 모든 페이지가 새롭게 그려져야 한다. 그렇기 때문에 부모 위젯을 stateful 로 한다 하더라도, 전체 구조에선 일부분이기 때문에 컴포넌트를 분리해야 효율적이다.
Share article