StatelessWidget vs StatefulWidget
1. Khái niệm
Trong Flutter, StatelessWidget và StatefulWidget là hai loại Widget cơ bản dùng để xây dựng giao diện.
Điểm khác biệt quan trọng nhất nằm ở State (trạng thái).
StatelessWidget: Widget không có State nội bộ có thể thay đổi.
StatefulWidget: Widget có State nội bộ có thể thay đổi trong quá trình ứng dụng chạy.
Có thể hiểu đơn giản:
StatelessWidget
→ UI phụ thuộc vào dữ liệu hiện tại
→ Không tự quản lý State thay đổi
StatefulWidget
→ UI có dữ liệu thay đổi
→ Có State để quản lý dữ liệu đó
2. StatelessWidget
StatelessWidget là Widget dùng để xây dựng những thành phần UI không cần quản lý trạng thái thay đổi bên trong Widget.
Ví dụ:
class WelcomeText extends StatelessWidget {
const WelcomeText({super.key});
@override
Widget build(BuildContext context) {
return const Text(
'Welcome to Flutter',
);
}
}
Widget trên chỉ hiển thị một dòng chữ.
Không có dữ liệu nào bên trong Widget cần thay đổi trong quá trình sử dụng.
Đặc điểm
StatelessWidget
├── Không có State riêng
├── Không sử dụng setState()
├── Có phương thức build()
├── UI phụ thuộc vào dữ liệu được cung cấp
└── Phù hợp với UI tĩnh hoặc UI không quản lý trạng thái nội bộ
3. Ví dụ StatelessWidget
Một ProductCard có thể được xây dựng bằng StatelessWidget:
class ProductCard extends StatelessWidget {
final String name;
final double price;
const ProductCard({
super.key,
required this.name,
required this.price,
});
@override
Widget build(BuildContext context) {
return Card(
child: Column(
children: [
Text(name),
Text('$price VNĐ'),
],
),
);
}
}
Sử dụng:
ProductCard(
name: 'Nike Air Max',
price: 2500000,
)
Ở đây ProductCard không tự thay đổi name hoặc price.
Nếu dữ liệu thay đổi, Widget cha có thể truyền dữ liệu mới xuống.
4. Khi nào sử dụng StatelessWidget?
Sử dụng StatelessWidget khi Widget:
• Chỉ hiển thị dữ liệu.
• Không có State nội bộ cần thay đổi.
• Không cần gọi setState().
• Có thể nhận dữ liệu từ Widget cha thông qua constructor.
Một số ví dụ:
Logo
Text
Icon
ProductCard
ProfileHeader
CustomButton
CategoryItem
StaticInformation
5. StatefulWidget
StatefulWidget là Widget được sử dụng khi giao diện cần quản lý dữ liệu có thể thay đổi trong quá trình ứng dụng chạy.
Ví dụ phổ biến:
Counter
Checkbox
Switch
TextField
Form
Loading
Animation
Tab
Like Button
Shopping Cart
Một StatefulWidget thường gồm hai phần:
StatefulWidget
↓
State<T>
↓
build()
Ví dụ:
class Counter extends StatefulWidget {
const Counter({super.key});
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int count = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('$count'),
ElevatedButton(
onPressed: () {
setState(() {
count++;
});
},
child: const Text('Increase'),
),
],
);
}
}
6. State
State là dữ liệu có thể thay đổi trong quá trình ứng dụng chạy và sự thay đổi đó có thể ảnh hưởng đến UI.
Ví dụ:
int count = 0;
Ban đầu:
count = 0
Người dùng nhấn nút:
count = 1
UI thay đổi:
0
↓
1
Đây chính là trường hợp cần sử dụng StatefulWidget.
7. setState()
setState() được sử dụng để thông báo cho Flutter rằng State đã thay đổi và UI cần được rebuild.
Ví dụ:
setState(() {
count++;
});
Quá trình hoạt động:
User click
↓
setState()
↓
State thay đổi
↓
build() được gọi lại
↓
UI cập nhật
Nếu chỉ viết:
count++;
Flutter không được thông báo rằng UI cần rebuild theo cơ chế StatefulWidget.
8. Cấu trúc StatefulWidget
Một StatefulWidget có cấu trúc khác StatelessWidget.
StatelessWidget
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
return const Text('Hello');
}
}
Chỉ cần một class.
StatefulWidget
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
@override
Widget build(BuildContext context) {
return const Text('Hello');
}
}
Thông thường sẽ có hai class:
MyWidget
↓
State<MyWidget>
↓
_MyWidgetState
Class StatefulWidget đại diện cho cấu hình của Widget.
Class State lưu trữ dữ liệu có thể thay đổi và xây dựng UI.
9. So sánh StatelessWidget và StatefulWidget
| Tiêu chí | StatelessWidget | StatefulWidget |
|---|---|---|
| Có State nội bộ | Không | Có |
| State thay đổi | Không quản lý | Có |
setState() |
Không | Có |
| Số class cơ bản | 1 | 2 |
Có build() |
Có | Có |
| UI có thể thay đổi | Có, khi nhận dữ liệu mới | Có, dựa trên State |
| Độ phức tạp | Thấp hơn | Cao hơn |
| Sử dụng | UI không cần State nội bộ | UI cần State thay đổi |
10. Một điểm dễ nhầm
StatelessWidget không có nghĩa là UI không bao giờ thay đổi.
Ví dụ:
class UserName extends StatelessWidget {
final String name;
const UserName({
super.key,
required this.name,
});
@override
Widget build(BuildContext context) {
return Text(name);
}
}
Widget này vẫn có thể hiển thị dữ liệu khác:
UserName(name: 'Tien')
sau đó Widget cha rebuild và truyền:
UserName(name: 'Minh')
UI sẽ thay đổi từ:
Tien
thành:
Minh
Nhưng bản thân UserName không tự quản lý State thay đổi.
Vì vậy, cách hiểu chính xác là:
StatelessWidget không có State nội bộ có thể thay đổi.
11. StatefulWidget không có nghĩa là toàn bộ Widget đều thay đổi
Khi State thay đổi:
setState(() {
count++;
});
Flutter gọi lại build() của State.
Flutter không đơn giản là xóa toàn bộ ứng dụng và vẽ lại từ đầu.
Flutter sử dụng Widget Tree, Element Tree và RenderObject Tree để xác định những phần cần được cập nhật.
12. Ví dụ thực tế
Nút Like
Nếu chỉ hiển thị một nút:
ElevatedButton(
onPressed: () {},
child: const Text('Like'),
)
Không nhất thiết cần StatefulWidget.
Nhưng nếu muốn khi nhấn nút thì số Like tăng:
Like: 0
↓
User click
↓
Like: 1
thì cần State để lưu số Like:
int likes = 0;
và cập nhật:
setState(() {
likes++;
});
Trường hợp này phù hợp với StatefulWidget.
13. Ví dụ thực tế trong ứng dụng thương mại điện tử
StatelessWidget
ProductCard:
ProductCard
├── Image
├── Product Name
├── Price
└── Rating
Nếu Widget chỉ nhận thông tin sản phẩm và hiển thị chúng thì có thể sử dụng StatelessWidget.
StatefulWidget
QuantitySelector:
Quantity: 1
[ - ] 1 [ + ]
Khi người dùng nhấn +:
1 → 2 → 3 → 4
Quantity thay đổi liên tục.
Do đó Widget có thể cần State:
int quantity = 1;
và:
setState(() {
quantity++;
});
14. Lifecycle cơ bản của StatefulWidget
StatefulWidget có vòng đời khác với StatelessWidget.
Một số phương thức quan trọng:
createState()
↓
initState()
↓
build()
↓
setState()
↓
build()
↓
dispose()
initState()
Được gọi một lần khi State được tạo.
@override
void initState() {
super.initState();
// Khởi tạo
}
Thường dùng để:
- Khởi tạo Controller.
- Đăng ký Listener.
- Khởi tạo dữ liệu.
- Thực hiện các thao tác cần chạy một lần.
dispose()
Được gọi khi State không còn được sử dụng.
@override
void dispose() {
controller.dispose();
super.dispose();
}
Thường dùng để giải phóng tài nguyên như:
- Controller.
- AnimationController.
- StreamSubscription.
- Listener.
15. Quy tắc lựa chọn
Có thể sử dụng quy tắc đơn giản:
Widget có State nội bộ thay đổi?
↓
Không
↓
StatelessWidget
Nếu:
Widget có State nội bộ thay đổi?
↓
Có
↓
StatefulWidget
Ví dụ:
Text
→ StatelessWidget
ProductCard
→ Thường là StatelessWidget
Counter
→ StatefulWidget
Checkbox
→ StatefulWidget
Switch
→ StatefulWidget
Form
→ Thường cần StatefulWidget hoặc cơ chế quản lý State khác
16. StatelessWidget và StatefulWidget trong kiến trúc ứng dụng
Trong ứng dụng thực tế, không phải mọi Widget có dữ liệu thay đổi đều nhất thiết phải tự quản lý State bằng StatefulWidget.
Ví dụ ứng dụng lớn có thể sử dụng:
Provider
Riverpod
Bloc
Cubit
GetX
để quản lý State bên ngoài Widget.
Khi đó nhiều Widget vẫn có thể là StatelessWidget nhưng UI vẫn thay đổi khi State Management cung cấp dữ liệu mới.
Vì vậy:
StatefulWidget là cách quản lý State cục bộ cơ bản của Flutter, không phải cách duy nhất để quản lý State trong ứng dụng.
17. Tóm tắt
StatelessWidget
│
├── Không quản lý State nội bộ
├── Không dùng setState()
├── Đơn giản
├── Phù hợp với UI không cần State nội bộ
└── Có thể nhận dữ liệu từ Widget cha
StatefulWidget
│
├── Có State
├── State có thể thay đổi
├── Có State class
├── Có thể sử dụng setState()
├── build() được gọi lại khi State thay đổi
└── Phù hợp với UI có trạng thái thay đổi
Cách nhớ nhanh
StatelessWidget = UI không có State nội bộ cần thay đổi.
StatefulWidget = UI có State nội bộ thay đổi trong quá trình chạy.
Ví dụ dễ nhớ nhất:
Text "Hello"
→ StatelessWidget
Counter 0 → 1 → 2 → 3
→ StatefulWidget






Khoá học lập trình game con rắn cho trẻ em




