Composition over Configuration
Composition model ของ React — component เล็กๆ ที่รับ children, higher-order components ที่ wrap behavior, และ render props — map ได้อย่างลงตัวกับ widget model ของ Flutter ใน Flutter คุณ compose behavior โดยการ wrap widget: Padding(child: ...), GestureDetector(child: ...), Opacity(child: ...) ไม่มี CSS class inheritance หรือ widget subclassing สำหรับการ customize รูปลักษณ์ ทุกอย่างคือ composition
การ Wrap Behavior
หัวข้อที่มีชื่อว่า “การ Wrap Behavior”// React — children propfunction Card({ children, elevated }) { return ( <div style={{ padding: 16, borderRadius: 12, boxShadow: elevated ? '0 4px 12px rgba(0,0,0,0.1)' : 'none', }} > {children} </div> );}
// Usage<Card elevated> <h3>Hello</h3> <p>Composed content</p></Card>// Flutter — wrapper widget with childclass AppCard extends StatelessWidget { final Widget child; final bool elevated; const AppCard({super.key, required this.child, this.elevated = false});
@override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: elevated ? [BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 12, offset: const Offset(0, 4))] : [], ), child: child, ); }}
// UsageAppCard( elevated: true, child: Column( children: [ Text('Hello', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), Text('Composed content'), ], ),)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: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AppCard(
elevated: true,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text('Getting Started', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 4),
Text('Learn the basics of Flutter composition.', style: TextStyle(color: Colors.grey)),
],
),
),
const SizedBox(height: 16),
AppCard(
elevated: true,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text('Widget Tree', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 4),
Text('Everything is a widget — compose, not configure.', style: TextStyle(color: Colors.grey)),
],
),
),
const SizedBox(height: 16),
AppCard(
elevated: true,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text('Declarative UI', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 4),
Text('UI = f(state) — the same idea you know from React.', style: TextStyle(color: Colors.grey)),
],
),
),
],
),
),
),
);
}
}
class AppCard extends StatelessWidget {
final Widget child;
final bool elevated;
const AppCard({super.key, required this.child, this.elevated = false});
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: elevated
? [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 12,
offset: const Offset(0, 4),
)
]
: [],
),
child: child,
);
}
}