Day 17: Stateful Widgets & Lifecycle

Master Flutter's StatefulWidget lifecycle from birth to death! Learn how setState() triggers rebuilds, when to use initState/dispose, and Flutter's internal update decision algorithm. Perfect for developers moving from basics to production-ready apps.

ဒီနေ့မှာတော့ မနေ့က ဆွေးနွေးသွားတဲ့ Stateless widget တွေရဲ့အဆက်ဖြစ်တဲ့ Stateful Widgets တွေအကြောင်းရယ်၊ သူ့ရဲ့ lifecycle နဲ့ ပတ်သက်တာတွေကို ဆက်လက်ပြီး ဆွေးနွေးသွားပါမယ်။

မနေ့က ဆွေးနွေးခဲ့တဲ့ Stateless widget ဆိုတာ ပုံသေကားချပ်လိုမျိုး ပြောင်းမရ​ ပြင်မရ အမျိုးအစားလို့ ပြောလို့ရပါတယ်။ သူ့ကို ပြောင်းချင်တဲ့အခါ အပြင်က value အသစ် ထည့်ပေးရုံက လွဲပြီးတော့ သူ့ထဲမှာက ပြောင်းလဲတာတွေ လုပ်လို့မရပါဘူး။ ဒါကို immutable ဖြစ်တယ်လို့လဲ​ခေါ်ပါတယ်။

class BrokenCounter extends StatelessWidget {
  int count = 0; // ❌ Can't change!

  @override
  Widget build(BuildContext context) {
    return Text('Count: $count');
  }
}

ဒီမှာဆို count ဆိုတဲ့ value ကို stateless widget ထဲမှာ ကြေငြာထားတာဖြစ်တဲ့အတွက် ဒီ value ကို အပြောင်းအလဲ လုပ်ပေးလို့မရပါဘူး။ ဒီတော့ interactive ဖြစ်တဲ့ UI တွေ တည်ဆောက်ချင်တဲ့အခါ ဘယ်လို လုပ်ကြမလဲ? ဒါကိုတော့ Stateful widget တွေ သုံးပြီးတော့ ဖြေရှင်းလို့ ရပါတယ်။

Stateful Widget

Stateful widget လို့ပြောရင် သူ့မှာ ၂ပိုင်းရှိပါတယ်။ တခုကတော့ widget ဖြစ်ပြီး နောက်တခုကတော့ state ပါ။

// THE SHELL (Immutable Configuration)
class CounterPage extends StatefulWidget {
  const CounterPage({super.key});
  
  @override
  State<CounterPage> createState() => _CounterPageState();
}

// THE BRAIN (Mutable Logic)
class _CounterPageState extends State<CounterPage> {
  int _count = 0; // This CAN change!
  
  @override
  Widget build(BuildContext context) {
    return Text('Count: $_count');
  }
}

The Widget Class

ဒါကိုတော့ အခွံလို့ မြင်ကြည့်လို့ရပါတယ်။ Stateless လိုမျိုးပဲ immutable ဖြစ်ပါတယ်။ သူ့ထဲမှာ value တွေကို ပြောင်းလဲလို့မရပါဘူး။

The State Class

ဒါကတော့ အဓိလုပ်ဆောင်ချက်တွေ ပါဝင်တဲ့ အစိတ်အပိုင်းပဲ ဖြစ်ပါတယ်။ mutable ဖြစ်နေမှာ ဖြစ်ပြီးတော့ သူ့ထဲက ပြောင်းလဲနေမယ့် data တွေကို ကိုယ်တိုင်ကိုယ်ကျ ကိုင်တွယ်ပေးပါတယ်။

State ကိုတော့ ရေးရင် underscore (_) နဲ့ ရေးပါတယ်။ (e.g., _CounterPageState) ဒီလိုရေးတာ dart ရဲ့ private အဖြစ် ကြေငြာတာလို့ ပြောခဲ့ပြီးသား ဖြစ်ပါတယ်။ အခုလို ကြေငြာလိုက်ခြင်းအားဖြင့် State class က Widget class တခုထဲက ခေါ်သုံးလို့ရတဲ့ private class ဖြစ်သွားပါတယ်။

Update State

ဒီတော့ stateful widget ထဲက value ကို ဘယ်လိုမျိုး အပြောင်းအလဲ လုပ်သလဲဆိုတော့ setState ဆိုတဲ့ function ကို ခေါ်ပြီး update လုပ်ပါတယ်။​

void _increment() {
  setState(() {
    _count++; // Change happens HERE
  });
}

setState ထဲမှာ ထည့်ရေးလိုက်ခြင်းအားဖြင့် အောက်မှာပေးထားတဲ့ အဆင့်တွေ တခုပြီးတခု Flutter engine က လုပ်ဆောင်သွားပါတယ်။

  1. setState ကို ခေါ်ပါတယ်
  2. Flutter engine က ဒီ setState ခေါ်လိုက်တဲ့ widget ကို dirty ဖြစ်သွားပြီလို့ သတ်မှတ်ပါတယ်
  3. Flutter engine ဒီ widget ကို re-build လုပ်ဖို့ ပြင်ဆင်ပါတယ် (schedule လုပ်ပါတယ်)
  4. build method ကို ထပ်ပြီးတော့ ခေါ်ပါတယ်
  5. UI အသစ်ကို ပြပေးပါတယ်

တကယ်လို့ setState နဲ့ မခေါ်ဘဲ အခုလိုမျိုး ခေါ်ရင်ရော ဘယ်လို ဖြစ်သွားမယ် ထင်ပါသလဲ?

void _increment() {
  count++; // Update value
}

ဒီမှာဆို _count value ကို တခုတိုးပေးလိုက်တာပဲ ဖြစ်ပါတယ်။ value ပြောင်းသွားပေမယ့် အပေါ်က အဆင့်တွေ ဖြတ်မသွားတဲ့အတွက် UI မှာတော့ ပြောင်းမသွားပါဘူး။

ဒါဆိုရင်တော့ CounterPage ဆိုပြီး အပေါ်မှာ ဆွေးနွေးခဲ့တဲ့ implementation တွေကို စုပြီးတော့ ရေးလိုက်ပါမယ်။

import 'package:flutter/material.dart';

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

  @override
  State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  // Our mutable state
  int _count = 0;

  void _increment() {
    setState(() {
      _count++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Stateful Counter")),
      body: Center(
        child: Text(
          "Total Taps: $_count",
          style: const TextStyle(fontSize: 30),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _increment,
        child: const Icon(Icons.add),
      ),
    );
  }
}

Floating Action Button ကို နှိပ်တိုင်းမှာ _count value က ပြောင်းနေမှာပဲ ဖြစ်ပါတယ်။

The Widget Lifecycle

Stateful widget မှာ lifecycle events တွေ ဆိုပြီးတော့ ရှိပါတယ်။ ဒါတွေကတော့ widget တခု စတင်ပြီး တည်ဆောက်တဲ့အချိန်ကနေ နောက်ဆုံး မသုံးတော့လို့ ဖျက်လိုက်တဲ့အထိ သုံးလို့ရတဲ့ callback function တွေပဲ ဖြစ်ပါတယ်။

Birth

@override
void initState() {
  super.initState();
  print("Widget is born!");
  // Initialize controllers, fetch API data, start timers
}

Widget ကို ပထမဆုံး တည်ဆောက်တဲ့အချိန်တော့ initState ကို ခေါ်ပါတယ်။ တကယ်လို့ widget ကို စတဲ့အချိန်မှာ ခေါ်ချင်တဲ့ API တွေ ရှိလို့ဖြစ်ဖြစ်၊ controller တွေ setup လုပ်ချင်တာဖြစ်ဖြစ်၊ timer တွေ စချင်တဲ့အခါဖြစ်ဖြစ် သုံးလို့ရပါတယ်။

Life

@override
Widget build(BuildContext context) {
  print("Building UI...");
  return Scaffold(...);
}

ဒါကိုတော့ setState ကို ခေါ်လိုက်တိုင်းမှာ build method ကို ပြန်ပြီးတော့ run ပါတယ်။ ဒါကြောင့် UI မှာ ပြောင်းထားတဲ့ အသစ်တွေကို မြင်ရတာပဲ ဖြစ်ပါတယ်။

Death

@override
void dispose() {
  // Cancel timers, close streams, dispose controllers
  print("Widget is dying...");
  super.dispose();
}

ဒါကိုတော့ widget ကို widget tree ကနေ ဖယ်ထုတ်ဖို့ လုပ်တဲ့အခါ မဖျက်ခင် ခေါ်ပါတယ်။​ တကယ်လို့ controller တွေ၊ subscription တွေ၊ timer တွေ ရှိတဲ့အခါ memory leak တွေ မဖြစ်အောင် dispose/close လုပ်ဖို့လိုတဲ့အခါ သုံးပါတယ်။

StatelessWidget vs StatefulWidget Preview

Feature StatelessWidget StatefulWidget
Data Changes No (immutable) Yes (mutable)
Performance ⚡⚡⚡⚡⚡ Faster ⚡⚡⚡⚡ Slightly slower
Lifecycle Only build() initState(), build(), dispose()
Use Cases Icons, labels, static cards Forms, animations, interactive elements
Memory Lightweight Small overhead for state management

ဒီတော့ stateless widget ကို ဖြစ်နိုင်သလောက် သုံးပြီးတော့ တကယ်လိုတဲ့အခါမှ stateful widget တွေကို သုံးပေးဖို့ တိုက်တွန်းပါတယ်။

တကယ့်လက်တွေမှာ ဘယ်လိုအခြေအနေတွေမှာ Stateful widget တွေ သုံးလဲ​ကြည့်ကြည့်ရအောင်ပါ။

  • Instagram Like Button: နှိပ်လိုက်တာနဲ့ icon ပြောင်းလဲတဲ့အခါမျိုး
  • Amazon Shopping Cart: item ကို buy ဖို့ နှိပ်လိုက်တာနဲ့ Cart item တိုးသွားတာမျိုး
  • Form Fields: user input လုပ်တိုင်း valid ဖြစ်၊မဖြစ် စစ်တာမျိုး

အစရှိတဲ့ အခြေအနေတွေမှာ သုံးပါတယ်။

ဒါဆိုရင်တော့ Stateful widget နဲ့ ပတ်သက်ပြီး အတော်လေး သိလောက်ပြီ ထင်ပါတယ်။


ဒီနေ့ Day 17 အတွက်ကတော့ ဒီလောက်ပဲ ဖြစ်ပါတယ်။ အဆုံးထိ ဖတ်ပေးတဲ့အတွက် အများကြီး ကျေးဇူးတင်ပါတယ်။ နားမလည်တာတွေ အဆင်မပြေတာတွေ ရှိခဲ့ရင်လဲ အောက်မှာပေးထားတဲ့ discord server ထဲမှာ လာရောက်ဆွေးနွေးနိုင်ပါတယ်။ နောက်နေ့တွေမှာလဲ ဆက်လက်ပြီး sharing လုပ်သွားပေးသွားမှာ ဖြစ်တဲ့အတွက် subscribe လုပ်ထားဖို့ ဖိတ်ခေါ်ပါတယ်။