setState vs useState
ใน React useState คือ hook ที่เก็บค่าและคืน setter กลับมา เรียก setter แล้ว React จะกำหนดเวลา re-render และ component function จะทำงานอีกครั้งพร้อมค่าใหม่ state อยู่ใน slot ซ่อนอยู่ที่ผูกกับ component instance
Flutter ใช้ setState(() { ... }) เป็นเทียบเท่า แต่ก่อนจะเรียกได้ คุณต้องมีสอง class แทนที่จะเป็นหนึ่ง — คือ StatefulWidget และ State<T> การแยกนี้ดูยาวเหนื่อยตอนแรก แต่แก้ปัญหาเฉพาะ: widget objects ใน Flutter เป็น immutable และ framework สามารถสร้างใหม่ได้ราคาถูก State object อยู่ได้นานกว่าและเก็บข้อมูลที่เปลี่ยนแปลงได้จริง
การเปรียบเทียบแบบ side-by-side
หัวข้อที่มีชื่อว่า “การเปรียบเทียบแบบ side-by-side”import { useState } from 'react';
function Counter() { const [count, setCount] = useState(0);
return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}> Increment </button> </div> );}class Counter extends StatefulWidget { const Counter({super.key});
@override State<Counter> createState() => _CounterState();}
class _CounterState extends State<Counter> { int _count = 0; // state อยู่ที่นี่
void _increment() { setState(() { // ครอบ mutation _count++; }); }
@override Widget build(BuildContext context) { return Column( children: [ Text('Count: $_count'), ElevatedButton( onPressed: _increment, child: const Text('Increment'), ), ], ); }}ตัวอย่างที่รันได้
หัวข้อที่มีชื่อว่า “ตัวอย่างที่รันได้”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: 'Counter',
theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo)),
home: const Scaffold(
body: Center(child: Counter()),
),
);
}
}
class Counter extends StatefulWidget {
const Counter({super.key});
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int _count = 0;
void _increment() => setState(() => _count++);
void _decrement() => setState(() => _count--);
void _reset() => setState(() => _count = 0);
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'$_count',
style: TextStyle(
fontSize: 72,
fontWeight: FontWeight.bold,
color: scheme.primary,
),
),
const SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FilledButton.tonal(onPressed: _decrement, child: const Text('−')),
const SizedBox(width: 12),
FilledButton(onPressed: _increment, child: const Text('+')),
const SizedBox(width: 12),
OutlinedButton(onPressed: _reset, child: const Text('Reset')),
],
),
],
);
}
}