Kodokon kodokon.com

การโต้ตอบ: ปุ่ม StatefulWidget และ setState

ทำให้หน้าจอของคุณมีชีวิตด้วยการตอบสนองต่อการแตะปุ่ม และอัปเดตการแสดงผลด้วย setState

10 นาที · 3 คำถาม

เปิดบทเรียนนี้ใน Kodokon

หน้าจอของเราสวยแต่นิ่งสนิท: ได้เวลาตอบสนองต่อท่าทางของผู้ใช้แล้ว ปุ่มมาตรฐานของ Material 3 คือ ElevatedButton มันรับพารามิเตอร์สำคัญสองตัว: child เนื้อหาที่มันแสดง (มักเป็น Text) และ onPressed ฟังก์ชันที่จะทำงานเมื่อคุณแตะมัน ฟังก์ชันที่ส่งเข้ามาในลักษณะนี้ในฐานะพารามิเตอร์เรียกว่า คอลแบ็ก (callback): คุณไม่ได้เรียกมันด้วยตัวเอง แต่ Flutter เรียกมันให้คุณในจังหวะที่เหมาะสม ไวยากรณ์ () { ... } สร้าง ฟังก์ชันนิรนาม (anonymous function) ที่ไม่มีชื่อ เขียนไว้ตรงจุดนั้นเลย

DART
import 'package:flutter/material.dart';

Widget buildHelloButton() {
  return ElevatedButton(
    onPressed: () {
      debugPrint("Button pressed!");
    },
    child: const Text("Tap here"),
  );
}
ปุ่มที่เขียนออกมาที่คอนโซลทุกครั้งที่แตะ

debugPrint เขียนออกมาที่คอนโซล... แต่ตัวหน้าจอเองไม่เปลี่ยน ทำไม? เพราะ StatelessWidget (วิดเจ็ต ไร้สเตต) นั้นนิ่งสนิท: เมื่อสร้างเสร็จแล้ว มันก็เปลี่ยนไม่ได้อีก ในการแสดงค่าที่เปลี่ยนแปลง คุณต้องใช้ StatefulWidget (วิดเจ็ต มีสเตต) สเตต (state) คือชุดข้อมูลที่เปลี่ยนแปลงได้ในระหว่างที่วิดเจ็ตมีชีวิตอยู่: ตัวนับ กล่องที่ถูกติ๊ก ข้อความที่พิมพ์ลงไป... StatefulWidget มักมาคู่กับคลาส State เสมอ ซึ่งเก็บข้อมูลนี้ไว้และบรรจุเมท็อด build นี่คือตัวอย่างคลาสสิกในตำนานจากยุคเริ่มต้น: ตัวนับ

DART
import 'package:flutter/material.dart';

void main() {
  runApp(const CounterApp());
}

class CounterApp extends StatelessWidget {
  const CounterApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: const CounterPage(),
    );
  }
}

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

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

class _CounterPageState extends State<CounterPage> {
  int count = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              "Counter: $count",
              style: const TextStyle(fontSize: 32),
            ),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: () {
                setState(() {
                  count = count + 1;
                });
              },
              child: const Text("+1"),
            ),
          ],
        ),
      ),
    );
  }
}
ตัวนับ: StatefulWidget ที่สมบูรณ์

กลไกนี้มีสามขั้นตอน 1) ตัวแปร count อยู่ใน _CounterPageState: นั่นคือสเตต 2) ในการแตะแต่ละครั้ง คอลแบ็กจะเรียก setState: เมท็อดนี้แก้ไขสเตต และบอก Flutter ว่ามีบางอย่างเปลี่ยนไป 3) จากนั้น Flutter จะรัน build ใหม่ ซึ่งวาดหน้าจอใหม่ด้วยค่าใหม่ของ count จำแนวคิดนี้ไว้: คุณไม่เคยเปลี่ยนหน้าจอโดยตรง คุณเปลี่ยน ข้อมูล แล้ว Flutter จะดูแลการแสดงผลเอง

ทดสอบความรู้

ตรวจสอบว่าคุณจำประเด็นสำคัญของบทเรียนนี้ได้ครบถ้วน

  1. พารามิเตอร์ onPressed ของ ElevatedButton มีไว้เพื่ออะไร?
    • เพื่อกำหนดข้อความที่แสดงบนปุ่ม
    • เพื่อจัดหาฟังก์ชันที่ทำงานเมื่อปุ่มถูกแตะ
    • เพื่อเลือกสีของปุ่ม
  2. เมื่อใดที่คุณควรใช้ StatefulWidget แทน StatelessWidget?
    • เมื่อการแสดงผลขึ้นอยู่กับข้อมูลที่เปลี่ยนแปลงไปตามเวลา
    • เมื่อวิดเจ็ตบรรจุลูกมากกว่าสามตัว
    • เมื่อคุณต้องการให้แอปเริ่มทำงานเร็วขึ้น
  3. จะเกิดอะไรขึ้นถ้าคุณเปลี่ยน count โดยไม่เรียก setState?
    • แอปพังทันที
    • ตัวแปรเปลี่ยนในหน่วยความจำแต่หน้าจอไม่ได้ถูกอัปเดต
    • Flutter เรียก setState ให้คุณโดยอัตโนมัติ