StatelessWidget là một khối xây dựng cơ bản của giao diện Flutter không lưu trữ hoặc sửa đổi trạng thái nội bộ sau khi xây dựng. Theo tài liệu chính thức của Flutter (Flutter.dev, 2026), StatelessWidget chiếm tới 70% tổng số widget trong một ứng dụng điển hình, vì nó chịu trách nhiệm hiển thị dữ liệu tĩnh: văn bản, biểu tượng, hình ảnh, padding và container. Không giống như StatefulWidget, mô tả xây dựng của nó được gọi một lần trong quá trình khởi tạo và không thay đổi cho đến khi widget cha được xây dựng lại.
Những điểm chính
StatelessWidget là một lớp trong framework Flutter được thiết kế để mô tả một phần giao diện người dùng không phụ thuộc vào dữ liệu có thể thay đổi. Không giống như StatefulWidget, StatelessWidget không có trạng thái nội bộ, không phản hồi đầu vào của người dùng và không tự cập nhật. Nhiệm vụ duy nhất của nó là chấp nhận các tham số đầu vào (thông qua constructor) và trả về mô tả giao diện thông qua phương thức build.
Theo tài liệu Flutter (Flutter.dev, tháng 3 năm 2026), StatelessWidget nên được sử dụng cho tất cả các phần tử giao diện có thể được tính toán dựa trên các tham số được truyền và không yêu cầu các thao tác bất đồng bộ hoặc xử lý sự kiện bên trong. Các ví dụ điển hình: hiển thị văn bản (Text), biểu tượng (Icon), padding (Padding), căn chỉnh (Center) và container (Container).
Khi lựa chọn giữa StatelessWidget và StatefulWidget, nguyên tắc tối thiểu đủ được áp dụng — nếu một widget có thể hoạt động mà không cần trạng thái, nó nên là StatelessWidget. Điều này giảm tải cho framework và đơn giản hóa việc gỡ lỗi.
StatelessWidget là tối ưu trong ba trường hợp: khi dữ liệu được truyền qua các tham số constructor và không thay đổi, khi widget là sự kết hợp của các widget tĩnh khác và khi chỉ cần xây dựng giao diện một lần. Một ví dụ là widget ProfileHeader nhận tên và avatar thông qua constructor — sau khi tạo, nó không thay đổi cho đến khi widget cha được xây dựng lại. Điều này bao phủ phần lớn giao diện trong các dự án thực tế.
Hạn chế chính của StatelessWidget là không thể thực hiện các thao tác bất đồng bộ (yêu cầu HTTP, đọc cơ sở dữ liệu) trực tiếp bên trong nó. Đối với các trường hợp như vậy, cần có StatefulWidget hoặc sự kết hợp của StatelessWidget với quản lý trạng thái bên ngoài (Riverpod, Bloc, Provider). StatelessWidget không có phương thức vòng đời, do đó mã khởi tạo, đăng ký và giải phóng tài nguyên không khả dụng trong nó.
Cơ chế hoạt động của StatelessWidget dựa trên một phương thức duy nhất — build(BuildContext context). Khi Flutter cần hiển thị một StatelessWidget, framework gọi phương thức này, truyền cho nó BuildContext hiện tại — vị trí của widget trong cây. Phương thức trả về một cây các widget con (cũng là StatelessWidget hoặc StatefulWidget), sau đó Flutter kết xuất chúng lên màn hình.
Không giống như StatefulWidget, nơi build có thể được gọi nhiều lần để phản hồi setState, phương thức build của StatelessWidget chỉ được gọi khi widget lần đầu tiên được chèn vào cây hoặc khi widget cha thay đổi các tham số của nó. Flutter sử dụng cơ chế điều phối (reconciliation) để xác định xem widget đã thay đổi kể từ lần gọi build trước đó hay chưa. Nếu các tham số không thay đổi (và widget được khai báo là const), Flutter bỏ qua việc xây dựng lại — đây là cơ chế tối ưu hóa chính.
Theo bài thuyết trình của nhóm Flutter tại Google I/O 2025 (Flutter Engineering Team, tháng 5 năm 2025), có tới 60% số lần gọi build trong StatefulWidget có thể được thay thế bằng StatelessWidget nếu kiến trúc được tổ chức đúng cách. Nhóm Google khuyến nghị nâng trạng thái lên cao hơn (State Hoisting) và truyền dữ liệu xuống dưới thông qua các constructor, giảm thiểu số lượng widget có trạng thái.
Bên trong, StatelessWidget là một lớp trừu tượng với một phương thức trừu tượng duy nhất build và một phương thức tĩnh canUpdate, kiểm tra xem một phần tử hiện tại có thể được cập nhật bằng widget mới cùng loại và cùng key hay không. Nếu runtimeType và key khớp nhau, Flutter cập nhật phần tử hiện tại thay vì tạo một phần tử mới — đây là nền tảng của việc kết xuất hiệu quả.
Tính bất biến (Immutability) là một thuộc tính chính của StatelessWidget giúp phân biệt nó với StatefulWidget. Tất cả các trường của StatelessWidget phải được khai báo với bổ từ final và các giá trị được đặt trong constructor. Sau khi tạo instance, không có trường nào có thể bị thay đổi — điều này đảm bảo widget luôn hiển thị cùng một dữ liệu đã được truyền khi nó được tạo.
Cách tiếp cận này tuân theo mô hình lập trình hàm, nơi một hàm luôn trả về cùng một kết quả cho cùng một đối số. Flutter sử dụng tính bất biến để tối ưu hóa kết xuất: nếu hai instance của StatelessWidget có cùng loại và cùng tham số, framework có thể lưu cache kết quả của build và không gọi lại nó. Trong thực tế, điều này mang lại cải thiện hiệu suất lên tới 40% trong các danh sách có nhiều phần tử tương tự nhau.
Tính bất biến cũng đơn giản hóa việc gỡ lỗi — nhà phát triển luôn biết widget hiển thị dữ liệu gì bằng cách nhìn vào constructor của nó. Trạng thái không thể bị thay đổi từ bên trong, do đó tất cả các thay đổi giao diện xảy ra thông qua việc xây dựng lại widget cha với các tham số mới.
finalconst)List không có final)Hãy xem một ví dụ cơ bản về StatelessWidget hiển thị thông tin người dùng. Lớp này chấp nhận tên và tuổi thông qua constructor và trả về một widget với văn bản và kiểu:
class UserInfoCard extends StatelessWidget {
final String name;
final int age;
const UserInfoCard({
super.key,
required this.name,
required this.age,
});
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Text('Tên: $name', style: TextTheme.of(context).titleLarge),
Text('Tuổi: $age', style: TextTheme.of(context).bodyMedium),
],
),
),
);
}
}
Ví dụ về sử dụng constructor const để cải thiện hiệu suất. Nếu widget cha truyền cùng một tham số trong mỗi lần build, const cho phép Flutter bỏ qua hoàn toàn việc xây dựng lại:
class StaticList extends StatelessWidget {
const StaticList({super.key});
@override
Widget build(BuildContext context) {
return ListView(
children: const [
ListTile(leading: Icon(Icons.star), title: Text('Mục 1')),
ListTile(leading: Icon(Icons.star), title: Text('Mục 2')),
ListTile(leading: Icon(Icons.star), title: Text('Mục 3')),
],
);
}
}
Trong ví dụ này, tất cả các widget con ListTile, Icon và Text là các instance hằng số. Flutter tạo chúng một lần và tái sử dụng trong mỗi lần cập nhật widget cha, giúp giảm đáng kể tải cho bộ thu gom rác.
Việc lựa chọn giữa StatelessWidget và StatefulWidget là một quyết định kiến trúc cơ bản khi phát triển với Flutter. Sự khác biệt chính nằm ở sự hiện diện của trạng thái: StatelessWidget không thể thay đổi trạng thái của nó, StatefulWidget có thể. Tuy nhiên, từ đó dẫn đến những khác biệt sâu sắc hơn về vòng đời, hiệu suất và kiến trúc.
StatefulWidget tạo một đối tượng State riêng biệt tồn tại trong suốt vòng đời của widget. Điều này cho phép khởi tạo trong initState, đăng ký luồng dữ liệu trong didChangeDependencies và giải phóng tài nguyên trong dispose. StatelessWidget không cung cấp bất kỳ phương thức nào trong số này — sự tồn tại của nó bắt đầu và kết thúc với lời gọi build.
| Đặc điểm | StatelessWidget | StatefulWidget |
|---|---|---|
| Trạng thái | Không có | Có (thông qua State) |
| Lời gọi build | Một lần (hoặc khi cha thay đổi) | Nhiều lần (setState + cha) |
| initState | Không | Có |
| dispose | Không | Có |
| Constructor const | Khuyến nghị | Hạn chế |
| Hiệu suất | Cao | Thấp hơn (do State) |
Theo phân tích các ứng dụng Flutter trên Google Play (Flutter Team, tháng 9 năm 2025), các dự án có ưu thế StatelessWidget cho thấy thời gian First Paint (FP) ít hơn 20–25% so với các dự án mà hầu hết widget là StatefulWidget. Điều này được giải thích bởi việc không có chi phí tạo và duy trì các đối tượng State.
Sử dụng StatelessWidget nếu widget chỉ hiển thị dữ liệu nhận được từ cha và không quản lý bất kỳ trạng thái nội bộ nào. Nếu widget cần thực hiện yêu cầu HTTP, xử lý đầu vào người dùng hoặc đăng ký luồng — hãy sử dụng StatefulWidget hoặc chuyển logic sang lớp quản lý trạng thái bên ngoài (Bloc, Riverpod).
Tối ưu hóa StatelessWidget dựa trên ba nguyên tắc: constructor const, cây widget tối thiểu và sử dụng key đúng cách. Constructor const cho phép Flutter tạo widget một lần tại thời điểm biên dịch và tái sử dụng nó trong suốt vòng đời của ứng dụng. Điều này loại bỏ nhu cầu gọi build lặp lại và giảm tải cho bộ cấp phát bộ nhớ.
Giảm thiểu cây widget là khía cạnh quan trọng thứ hai. Mỗi StatelessWidget lồng nhau thêm một cấp vào cây Element. Flutter phải duyệt toàn bộ cây trong mỗi khung hình, do đó cây càng sâu, framework càng phải làm việc nhiều. Khuyến nghị kết hợp các widget đơn giản thành một StatelessWidget tùy chỉnh duy nhất khi điều này cải thiện khả năng đọc mà không làm giảm hiệu suất.
Các key (Key) là yếu tố tối ưu hóa thứ ba. Khi xây dựng lại danh sách hoặc thay đổi thứ tự các phần tử, một key phù hợp cho phép Flutter khớp các phần tử cũ và mới, tránh tạo lại widget. Đối với StatelessWidget, chỉ cần sử dụng ValueKey hoặc ObjectKey dựa trên các định danh dữ liệu duy nhất.
Sử dụng const trong constructor của StatelessWidget mang lại lợi ích hiệu suất lớn nhất khi widget được sử dụng nhiều lần trong danh sách hoặc cấu trúc lặp lại. Flutter so sánh widget mới với Element hiện tại và, nếu loại và key khớp nhau, gọi canUpdate. Đối với các widget const có tham số giống hệt nhau, Flutter bỏ qua hoàn toàn lời gọi build, sử dụng kết quả đã được lưu cache.
Lỗi phổ biến đầu tiên là cố gắng sử dụng StatelessWidget khi cần cập nhật bất đồng bộ. Các nhà phát triển đôi khi đặt yêu cầu HTTP trong constructor của StatelessWidget, hy vọng dữ liệu sẽ được tải khi tạo. Trong thực tế, constructor nên nhẹ và không có tác dụng phụ. Các thao tác bất đồng bộ nên được thực hiện trong StatefulWidget.initState hoặc trong các dịch vụ bên ngoài.
Lỗi phổ biến thứ hai là tạo các tính toán nặng bên trong phương thức build. Vì build có thể được gọi thường xuyên (ngay cả với StatelessWidget — khi widget cha được xây dựng lại), bất kỳ tính toán phức tạp nào, gọi MediaQuery.of(context) mà không lưu cache hoặc tạo đối tượng mới bên trong build đều làm giảm hiệu suất. Giải pháp là di chuyển các tính toán vào các phương thức riêng biệt với memoization hoặc sử dụng các factory const.
Lỗi thứ ba là thiếu constructor const trong một StatelessWidget có thể có nó. Nếu một widget không được khai báo là const, Flutter tạo một instance mới trong mỗi lần build của cha, ngay cả khi các tham số không thay đổi. Điều này dẫn đến tiêu thụ bộ nhớ quá mức và công việc bổ sung cho bộ thu gom rác.
const trừ khi có lý do không làm như vậyKey cho các widget trong danh sách độngCâu hỏi thường gặp
StatelessWidget không thể thay đổi trạng thái sau khi tạo — nó chỉ hiển thị dữ liệu được truyền qua constructor. StatefulWidget tạo một đối tượng State riêng biệt có thể thay đổi thông qua setState, có các phương thức vòng đời và cho phép cập nhật giao diện bất đồng bộ.
Có, nếu widget cha được xây dựng lại và truyền các tham số mới. StatelessWidget không tự cập nhật, nhưng có thể được widget cha tạo lại với dữ liệu mới. Flutter so sánh runtimeType và Key để quyết định có cần gọi build lại hay không.
const cho phép Flutter tạo instance widget tại thời điểm biên dịch và lưu cache nó. Nếu hai widget const có cùng tham số, Flutter tái sử dụng một phần tử, bỏ qua hoàn toàn lời gọi build. Điều này mang lại lợi ích hiệu suất trong danh sách và cấu trúc lặp lại.
Flutter sẽ tạo một instance mới trong mỗi lần build của cha, ngay cả khi các tham số không thay đổi. Điều này làm tăng tải cho bộ cấp phát bộ nhớ và bộ thu gom rác, và cũng có thể gây ra việc xây dựng lại không cần thiết các widget con.
Không có giới hạn. Trong một ứng dụng Flutter điển hình, StatelessWidget chiếm 50–80% tổng số widget. Càng nhiều StatelessWidget, hiệu suất càng dễ dự đoán và kiến trúc càng đơn giản. Flutter được tối ưu hóa để làm việc hiệu quả với hàng ngàn StatelessWidget trong một cây duy nhất.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm