© Khmer Angkor Academy - sophearithput168

Stateless Widgets

Stateless Widgets

Stateless Widget គឺជា widget ដែលមិនផ្លាស់ប្តូរ state។ ពួកវា immutable និងមាន performance ល្អ។ Build method ត្រូវបានហៅតែម្តងប៉ុណ្ណោះ លុះត្រាតែ parent widget rebuild។

📚 Stateless Widget Theory

Widget Lifecycle (Stateless):

Stateless Widget Lifecycle (Simple!)

1️⃣ Constructor called
   ↓
2️⃣ build() called
   ↓
3️⃣ Widget displayed
   ↓
4️⃣ Parent rebuilds → build() called again
   ↓
5️⃣ Widget removed from tree (disposed)

Note: No setState(), no state changes!
Only rebuilds when parent changes.

Characteristics:

Feature Description
Immutability Properties marked as final, cannot change
Performance ⚡ Fast - no state management overhead
Rebuild Trigger Only when parent widget rebuilds
Use Cases Static UI, labels, icons, layouts
Memory Lower memory footprint

🎯 ពេលណាប្រើ Stateless?

  • 📄 Static Content: Text, Images, Icons that don't change
  • 🎨 Layout Widgets: Container, Row, Column, Padding
  • 🔢 Display Data: Show information from parent (no interaction)
  • Performance Critical: Lists with thousands of items
  • 📦 Reusable Components: Buttons, cards, badges

🎯 Golden Rule: Use Stateless whenever possible! Only use Stateful when you truly need to manage changing state internally.

📝 Stateless Widget Structure

Basic Template:

import 'package:flutter/material.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text('Hello'),
    );
  }
}

With Constructor Parameters (Recommended):

class GreetingCard extends StatelessWidget {
  // All properties must be final (immutable)
  final String name;
  final String message;
  final Color? backgroundColor;
  
  // Constructor with named parameters
  const GreetingCard({
    Key? key,
    required this.name,
    required this.message,
    this.backgroundColor,
  }) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Container(
      color: backgroundColor ?? Colors.blue,
      padding: EdgeInsets.all(16),
      child: Column(
        children: [
          Text(
            'Hello, ' + name + '!',
            style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
          ),
          SizedBox(height: 8),
          Text(message),
        ],
      ),
    );
  }
}

// Usage
GreetingCard(
  name: 'សុខា',
  message: 'សូមស្វាគមន៍មកកាន់ Flutter!',
  backgroundColor: Colors.green,
)

Why use 'const' constructor?

// Without const - Creates new instance each rebuild
MyWidget(child: Text('Hello'))

// With const - Reuses same instance (better performance!)
const MyWidget(child: const Text('Hello'))

// Flutter can optimize:
// - No unnecessary rebuilds
// - Lower memory usage
// - Faster widget comparison

✅ Real-World Examples

1. Profile Card (Complex Layout)

class ProfileCard extends StatelessWidget {
  final String name;
  final String role;
  final String imageUrl;
  
  const ProfileCard({
    Key? key,
    required this.name,
    required this.role,
    required this.imageUrl,
  }) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: EdgeInsets.all(16),
        child: Row(
          children: [
            CircleAvatar(
              radius: 30,
              backgroundImage: NetworkImage(imageUrl),
            ),
            SizedBox(width: 16),
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  name,
                  style: TextStyle(
                    fontSize: 18,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                SizedBox(height: 4),
                Text(
                  role,
                  style: TextStyle(color: Colors.grey),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

2. Custom Button Component

class CustomButton extends StatelessWidget {
  final String text;
  final VoidCallback onPressed;
  final Color color;
  final IconData? icon;
  
  const CustomButton({
    Key? key,
    required this.text,
    required this.onPressed,
    this.color = Colors.blue,
    this.icon,
  }) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      style: ElevatedButton.styleFrom(
        backgroundColor: color,
        padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(8),
        ),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          if (icon != null) ...[
            Icon(icon),
            SizedBox(width: 8),
          ],
          Text(text, style: TextStyle(fontSize: 16)),
        ],
      ),
    );
  }
}

// Usage
CustomButton(
  text: 'Submit',
  icon: Icons.send,
  color: Colors.green,
  onPressed: () {
    print('Button clicked!');
  },
)

3. Product Card for E-commerce

class ProductCard extends StatelessWidget {
  final String name;
  final double price;
  final String imageUrl;
  final double rating;
  final VoidCallback onTap;
  
  const ProductCard({
    Key? key,
    required this.name,
    required this.price,
    required this.imageUrl,
    required this.rating,
    required this.onTap,
  }) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onTap,
      child: Card(
        elevation: 4,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Image
            AspectRatio(
              aspectRatio: 16 / 9,
              child: Image.network(
                imageUrl,
                fit: BoxFit.cover,
              ),
            ),
            Padding(
              padding: EdgeInsets.all(12),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  // Name
                  Text(
                    name,
                    style: TextStyle(
                      fontSize: 16,
                      fontWeight: FontWeight.bold,
                    ),
                    maxLines: 2,
                    overflow: TextOverflow.ellipsis,
                  ),
                  SizedBox(height: 8),
                  // Price & Rating
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Text(
                        '\$' + price.toStringAsFixed(2),
                        style: TextStyle(
                          fontSize: 18,
                          color: Colors.green,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      Row(
                        children: [
                          Icon(Icons.star, color: Colors.amber, size: 16),
                          SizedBox(width: 4),
                          Text(rating.toString()),
                        ],
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

4. Info Badge

class InfoBadge extends StatelessWidget {
  final String label;
  final IconData icon;
  final Color color;
  
  const InfoBadge({
    Key? key,
    required this.label,
    required this.icon,
    this.color = Colors.blue,
  }) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6),
      decoration: BoxDecoration(
        color: color.withOpacity(0.1),
        borderRadius: BorderRadius.circular(20),
        border: Border.all(color: color),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(icon, size: 16, color: color),
          SizedBox(width: 6),
          Text(
            label,
            style: TextStyle(
              color: color,
              fontWeight: FontWeight.w600,
            ),
          ),
        ],
      ),
    );
  }
}

// Usage
InfoBadge(
  label: 'Premium',
  icon: Icons.star,
  color: Colors.amber,
)

🎨 Composition Pattern

Build complex UIs by combining simple Stateless Widgets:

class UserProfile extends StatelessWidget {
  final String name;
  final String email;
  final String bio;
  final String avatarUrl;
  
  const UserProfile({
    Key? key,
    required this.name,
    required this.email,
    required this.bio,
    required this.avatarUrl,
  }) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        _buildAvatar(),
        SizedBox(height: 16),
        _buildName(),
        SizedBox(height: 8),
        _buildEmail(),
        SizedBox(height: 16),
        _buildBio(),
      ],
    );
  }
  
  Widget _buildAvatar() {
    return CircleAvatar(
      radius: 50,
      backgroundImage: NetworkImage(avatarUrl),
    );
  }
  
  Widget _buildName() {
    return Text(
      name,
      style: TextStyle(
        fontSize: 24,
        fontWeight: FontWeight.bold,
      ),
    );
  }
  
  Widget _buildEmail() {
    return Text(
      email,
      style: TextStyle(color: Colors.grey),
    );
  }
  
  Widget _buildBio() {
    return Text(
      bio,
      textAlign: TextAlign.center,
      style: TextStyle(fontSize: 14),
    );
  }
}

💡 Best Practices:

  • ✅ Mark all properties as final
  • ✅ Use const constructor when possible
  • ✅ Keep widgets small and focused (single responsibility)
  • ✅ Extract helper methods for complex UI parts
  • ✅ Use required for mandatory parameters
  • ✅ Provide default values for optional parameters
  • ✅ Add Key? key parameter for widget identification

⚠️ Common Mistakes:

  • ❌ Forgetting to mark properties as final
  • ❌ Using Stateful Widget when Stateless would work
  • ❌ Not using const (missing performance gains)
  • ❌ Creating too large/complex widgets (hard to maintain)
  • ❌ Trying to modify properties after creation (compile error!)

💡 ជំនួយ: ប្រើ Stateless Widget នៅពេលដែលអាច។ វាមាន performance ល្អជាង Stateful Widget។ Properties ត្រូវតែ final។ Use const constructor for optimization។