Lifting State Up

Pattern พื้นฐานใน Flutter สำหรับ share state ระหว่าง widget — ย้าย state ขึ้นไปยัง parent widget ที่เป็น ancestor ร่วมของ widgets ที่ต้องใช้ state นั้น

ปัญหา

StartScreen กับ QuestionsScreen ต้อง share state (activeScreen) แต่เป็น sibling กัน → ส่ง state ตรงๆ ระหว่างกันไม่ได้

Quiz (parent)
  ├── StartScreen      ← ต้องรู้ว่าเมื่อไหร่ควรเปลี่ยนหน้า
  └── QuestionsScreen  ← ต้องรู้ว่าเมื่อไหร่ควรแสดง

วิธีแก้

ย้าย state + logic ไปไว้ที่ parent (Quiz) แล้วส่ง function ลงไปให้ children:

class _QuizState extends State<Quiz> {
  var activeScreen = 'start-screen';
  List<String> selectedAnswers = [];
 
  void switchScreen() {
    setState(() { activeScreen = 'questions-screen'; });
  }
 
  void chooseAnswer(String answer) {
    selectedAnswers.add(answer);
    if (selectedAnswers.length == questions.length) {
      setState(() { activeScreen = 'results-screen'; });
    }
  }
 
  @override
  Widget build(BuildContext context) {
    return activeScreen == 'start-screen'
        ? StartScreen(switchScreen)                    // ส่ง function ลงไป
        : QuestionsScreen(onSelectAnswer: chooseAnswer);
  }
}
// StartScreen รับ function จาก parent
class StartScreen extends StatelessWidget {
  const StartScreen(this.startQuiz, {super.key});
  final void Function() startQuiz;
 
  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: startQuiz,  // ← เรียก function ของ parent
      child: const Text('Start Quiz'),
    );
  }
}

หลักการ

  1. หา ancestor ร่วม ของ widgets ที่ต้อง share state
  2. ย้าย state ไปไว้ที่ ancestor นั้น (ทำเป็น StatefulWidget)
  3. ส่ง data ลงไป ผ่าน constructor (ค่าที่อ่าน)
  4. ส่ง function ลงไป ผ่าน constructor (ค่าที่เปลี่ยน)

ข้อจำกัด

เมื่อ widget tree ลึกหลายชั้น → ต้องส่ง state ผ่าน constructor ทีละชั้น (prop drilling):

Parent (เก็บ state)
  → Child A (ส่งต่อ)
    → Child B (ส่งต่อ)
      → Child C (ใช้จริง)  ← ต้องผ่าน 3 ชั้น!

แก้ด้วย: Riverpod หรือ state management package อื่น

Key Points

  • ย้าย state ขึ้น parent ที่เป็น ancestor ร่วม → ส่ง function ลงมา
  • Pattern นี้ใช้ได้ดีกับแอปขนาดเล็ก (2-3 widget share state)
  • เมื่อ tree ลึก → prop drilling ยุ่งยาก → ย้ายไปใช้ Riverpod
  • State Management — ภาพรวม state management ทุกระดับ
  • Riverpod — ทางเลือกเมื่อ lifting state up ไม่เพียงพอ
  • Flutter — framework ที่ใช้ pattern นี้
  • Widgets — StatefulWidget เก็บ state ที่ถูก lift ขึ้นมา