[Flutter #8] Flutter 상태(State) 이해하기

도경원's avatar
Sep 27, 2025
[Flutter #8] Flutter 상태(State) 이해하기
플러터(Flutter)를 배우면서 가장 많이 나오는 개념이 바로 상태(State)입니다.
이번 글에서는 상태가 무엇인지, StatelessWidgetStatefulWidget의 차이, context, setState, 그리고 const까지 정리해봅니다.

1. 상태(State)란?

  • 상태(State) = 객체가 가지고 있는 값, 그리고 그 값이 변할 수 있는지 여부
  • 모든 객체는 상태를 가진다.
    • 예) int num = 1; → 상태는 1
  • 중요한 건 상태가 변하는가, 변하지 않는가 이다.
👉 Setter가 없는 객체 = 불변 상태(Immutable)
👉 Setter가 있어 값이 바뀔 수 있는 객체 = 가변 상태(Mutable)

서버의 상태 vs Flutter의 상태

  • 서버에서의 상태
    • "사용자의 세션, 로그인 정보, DB에 저장된 값" 같은 데이터의 지속성(Persistence)을 의미
    • 예) 로그인 세션 유지, 장바구니 상태, DB 레코드 값
    • 상태가 서버 메모리나 데이터베이스에 계속 보존
  • Flutter에서의 상태
    • 화면(UI)이 현재 어떤 값을 보여주고 있는지를 의미
    • 예) Counter 앱에서 숫자 값, 입력창에 적힌 텍스트, 체크박스 선택 여부
    • 앱 실행 중 메모리에만 존재하며, setState()나 상태관리 툴(Riverpod, Bloc 등)을 통해 UI 리빌드와 직결

정리
서버의 상태는 데이터의 지속성과 관리에 초점이 있고,
Flutter의 상태는 UI가 지금 어떻게 그려져야 하는가에 초점이 있습니다.

2. Stateless vs Stateful

  • 상태가 변하지 않는 위젯 → StatelessWidget
  • 상태가 변하는 위젯 → StatefulWidget
즉, Stateless와 Stateful의 차이는 상태의 변경 가능 여부라고 볼 수 있습니다.

예시

class HomePage extends StatefulWidget { @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { int num = 1; void increase() { num++; setState(() {}); // 상태 변경 후 화면 리빌드 } @override Widget build(BuildContext context) { return Scaffold( body: Center(child: Text("$num", style: TextStyle(fontSize: 50))), floatingActionButton: FloatingActionButton(onPressed: increase), ); } }
increase()가 실행되면 num이 바뀌고, setState()가 호출되어 화면이 다시 그려집니다.
setState() Stateful에서만 가능하고, createState()를 호출한다(리빌드)

3. Context란?

  • BuildContext = 도화지(Canvas) 같은 개념
  • 위젯 트리에서 위젯이 어디에 위치하는지 알려주는 좌표 역할을 합니다.
👉 따라서 context를 통해 부모 위젯, 테마, 미디어쿼리 정보 등에 접근할 수 있습니다.
notion image

4. 상태와 행위의 분리 문제

상태와 행위가 서로 다른 위젯에 있으면 문제가 생깁니다.
class Header extends StatefulWidget { @override State<Header> createState() => _HeaderState(); } class _HeaderState extends State<Header> { int num = 1; // 상태 @override Widget build(BuildContext context) => Text("$num"); } class Bottom extends StatelessWidget { @override Widget build(BuildContext context) { return ElevatedButton( onPressed: () {}, // 행위 child: Text("증가"), ); } }
여기서는 상태는 Header에 있고, 행위(증가 버튼)는 Bottom에 있어서 서로 연결되지 않음 → 동작이 안 됨.

해결 방법

  • 부모가 StatefulWidget이 되고, 상태와 행위를 관리
  • 자식 위젯에는 상태 값과 함수(행위)를 props로 전달
class _HomePageState extends State<HomePage> { int num = 1; void increase() => setState(() => num++); @override Widget build(BuildContext context) { return Column( children: [ Header(num), Bottom(increase), ], ); } }
notion image

5. const의 의미

  • const불변 객체를 의미합니다.
  • 한 번 만들어지면 리빌드되어도 다시 생성되지 않음 (성능 최적화 효과)
  • const를 쓰려면 내부 필드도 반드시 final이어야 함.
class Middle extends StatelessWidget { final int num; const Middle(this.num); @override Widget build(BuildContext context) { print("middle $num"); return Container(color: Colors.white); } }
👉 같은 const Middle(1)을 여러 번 호출해도 동일한 인스턴스를 재사용합니다.

6. 위젯 트리와 비용

notion image
  • 가짜 Stateful 위젯을 만든다.
  • setState()를 호출하면 해당 위젯의 전체 하위 트리(children가 다시 빌드됩니다.)
  • 그래서 상태와 행위는 가급적 묶어두는 것이 비용 관리 측면에서 유리합니다.
  • 불변 위젯(const)을 적극적으로 사용하면 불필요한 리빌드를 줄일 수 있습니다.

📌 정리

  1. 모든 객체는 상태를 가진다 → 변하는지, 불변인지가 중요
  1. Stateless = 불변, Stateful = 변할 수 있음
  1. context는 위젯의 도화지(위치 정보)
  1. setState() = 상태 변경 후 리빌드 트리거
  1. 상태와 행위는 부모에서 묶어 자식에게 전달 (Props)
  1. const는 성능 최적화의 핵심 → 동일 객체 재사용
  1. 위젯 트리 전체 리빌드를 줄이려면 구조 설계가 중요

 
Share article

Gyeongwon's blog