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

Props & Constructors

ใน React คุณส่งข้อมูลให้ component ผ่าน props ที่เป็น object ธรรมดาที่ destructure ใน signature ของฟังก์ชัน ส่วนใน Flutter คุณส่งข้อมูลให้ widget ผ่าน constructor parameter ที่ประกาศเป็น field แบบ final บน class ทั้งสองโมเดลแก้ปัญหาเดียวกันเป๊ะ คือทำให้ widget ปรับแต่งได้จากภายนอกโดยไม่ผูกติดกับแหล่งข้อมูลใดแหล่งข้อมูลหนึ่ง

Flutter ใช้ named parameter ของ Dart อย่างหนัก named parameter เป็นแบบ opt-in คือเมื่อห่อด้วย {} จะกลายเป็น keyword argument ตอนเรียกใช้ ถ้าทำเครื่องหมายตัวใดเป็น required Dart จะบังคับใช้ตอน compile ไม่ต้องพึ่ง PropTypes หรือ Required<> ของ TypeScript อีกต่อไป

React
// React — TypeScript props
interface BadgeProps {
label: string;
color?: string; // optional, has default
count: number; // required
}
function Badge({ label, color = 'blue', count }: BadgeProps) {
return (
<span style={{ background: color }}>
{label} ({count})
</span>
);
}
// Usage
<Badge label="Notifications" count={5} />
<Badge label="Alerts" color="red" count={2} />
Flutter
// Flutter — constructor params
class Badge extends StatelessWidget {
final String label;
final Color color; // optional with default
final int count; // required
const Badge({
super.key,
required this.label,
this.color = Colors.blue, // default value
required this.count,
});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(12),
),
child: Text(
'$label ($count)',
style: const TextStyle(color: Colors.white),
),
);
}
}
// Usage
Badge(label: 'Notifications', count: 5)
Badge(label: 'Alerts', color: Colors.red, count: 2)
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(
      home: Scaffold(
        backgroundColor: Colors.grey[100],
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: const [
              StatusBadge(label: 'Active', status: BadgeStatus.success),
              SizedBox(height: 12),
              StatusBadge(label: 'Pending', status: BadgeStatus.warning),
              SizedBox(height: 12),
              StatusBadge(label: 'Failed', status: BadgeStatus.error),
            ],
          ),
        ),
      ),
    );
  }
}

enum BadgeStatus { success, warning, error }

class StatusBadge extends StatelessWidget {
  final String label;
  final BadgeStatus status;
  final double fontSize;

  const StatusBadge({
    super.key,
    required this.label,
    required this.status,
    this.fontSize = 14,
  });

  Color get _color {
    switch (status) {
      case BadgeStatus.success: return Colors.green;
      case BadgeStatus.warning: return Colors.orange;
      case BadgeStatus.error:   return Colors.red;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      decoration: BoxDecoration(
        color: _color.withOpacity(0.15),
        border: Border.all(color: _color),
        borderRadius: BorderRadius.circular(20),
      ),
      child: Text(
        label,
        style: TextStyle(color: _color, fontSize: fontSize,
            fontWeight: FontWeight.w600),
      ),
    );
  }
}
คุณประกาศ named parameter แบบ required ใน constructor ของ Flutter widget อย่างไร?
ทำไม field ของ widget จึงประกาศเป็น `final` ใน Flutter?
`this.fieldName` แบบย่อในรายการพารามิเตอร์ของ Dart constructor ทำอะไร?