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 counter (baseline ของคุณ)
หัวข้อที่มีชื่อว่า “React counter (baseline ของคุณ)”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 counter — the default generated appimport '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 ที่มี useStateclass 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'), ), ], ), ), ); }}Default app แบบสมบูรณ์ — รันได้จริง
หัวข้อที่มีชื่อว่า “Default app แบบสมบูรณ์ — รันได้จริง”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 มีข้อจำกัด (teaser)
หัวข้อที่มีชื่อว่า “setState มีข้อจำกัด (teaser)”setState ทำงานได้ดีสำหรับ local UI state — เหมือน useState แต่เมื่อ state ต้องแชร์ระหว่าง widget หลายตัว Flutter developer จะใช้ Riverpod (หรือ Provider/Bloc) — เหตุผลเดียวกับที่ React developer ย้ายจาก useState ไป Zustand หรือ Redux สำหรับ shared state module State & Lifecycle จะครอบคลุมเรื่องนี้อย่างละเอียด