ข้ามไปยังเนื้อหา

Flutter App แรก — Counter

เมื่อรัน flutter create my_app app ที่ generate ขึ้นมาคือ counter — “Hello World” เดียวกับที่ React tutorial ใช้แนะนำ useState logic เหมือนกันทุกประการ แค่ syntax ต่างกัน บทเรียนนี้จะ walk through ทั้งสองแบบ side by side เพื่อให้เห็นว่า React knowledge ของคุณ map ตรงไหน

React
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div style={{ textAlign: 'center', marginTop: 60 }}>
<h2>Count: {count}</h2>
<button onClick={() => setCount(c => c + 1)}>
Increment
</button>
</div>
);
}
Flutter
// Flutter counter — the default generated app
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: CounterPage());
}
}
// StatefulWidget = component ที่มี useState
class CounterPage extends StatefulWidget {
const CounterPage({super.key});
@override
State<CounterPage> createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
int _count = 0; // ≈ const [count, setCount] = useState(0)
void _increment() {
setState(() { // ≈ setCount(c => c + 1)
_count++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('Count: $_count',
style: const TextStyle(fontSize: 28)),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _increment,
child: const Text('Increment'),
),
],
),
),
);
}
}

App ด้านล่างคือ default Flutter counter ที่ polish เล็กน้อย กดปุ่มแล้วดู count อัปเดต — เหมือน React version ทุกประการ

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Counter',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
        useMaterial3: true,
      ),
      home: const CounterPage(title: 'Flutter Counter'),
    );
  }
}

class CounterPage extends StatefulWidget {
  final String title;
  const CounterPage({super.key, required this.title});

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

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('You have pushed the button this many times:'),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.displayMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _increment,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

setState ทำงานได้ดีสำหรับ local UI state — เหมือน useState แต่เมื่อ state ต้องแชร์ระหว่าง widget หลายตัว Flutter developer จะใช้ Riverpod (หรือ Provider/Bloc) — เหตุผลเดียวกับที่ React developer ย้ายจาก useState ไป Zustand หรือ Redux สำหรับ shared state module State & Lifecycle จะครอบคลุมเรื่องนี้อย่างละเอียด

Flutter StatefulWidget แบ่งเป็นสอง class แต่ละ class เก็บอะไร?
Flutter equivalent ของการเรียก React state setter (`setCount`) คืออะไร?
`Scaffold` widget ให้อะไรบ้าง?
ใน Dart underscore นำหน้าชื่อ field (เช่น `_counter`) หมายความว่าอะไร?