---
title: "So sánh StatelessWidget và StatefulWidget"
description: "Trong bài viết này, các bạn sẽ có cái nhìn tổng quát về hai loại widget lớn nhất là StatelessWidget và StatefulWidget."
canonical: "https://200lab.io/blog/statelesswidget-vs-statefulwidget"
published: "2022-07-17T14:28:56Z"
updated: "2026-08-21T07:17:36Z"
authors: ["Vân Lê"]
tags: ["Flutter"]
reading_minutes: 12
access: "public"
---

## 1. Intro

Xin chào các bạn, đây là bài viết đầu tiên của mình trên blog của cộng đồng **200lab**. Trước đây mình cũng đã có một số bài viết khác về Flutter và được đăng trên github cá nhân của mình. Mọi người có thể follow tại [đây](<https://github.com/vanle57>). Bây giờ thì bắt đầu thôi nào!

## 2. Mở đầu

Khi tiếp xúc với Flutter, có lẽ các bạn đều đã quen hoặc nếu không quen thì cũng đã từng nghe câu “Everything is a widget!” – có nghĩa là tất cả mọi thứ đều là widget. Text là một widget, Button là một Widget, các Animation cũng là Widget, thậm chí bản thân app cũng là một Widget. Nghe nhiều là vậy nhưng thực chất các widget này lại được chia thành hai nhóm chính là StalessWidget và StatefulWidget.

Mình cũng khá chắc là trong số những bạn đang đọc bài viết này cũng có một số bạn đã biết về hai loại này nhưng để hiểu về nó thì còn khá mơ hồ. Vậy nên bài viết này mình sẽ cố gắng trình bày về chúng một cách đơn giản nhất có thể để các bạn nắm bắt được.

## 3. Chuẩn bị

- IDE:

- Visual Studio Code version 1.67.0
- Android Studio Chipmunk 2021.2.1
- XCode version 13.3.1
- Flutter SDK version 2.10.5
- Kiến thức: ngôn ngữ lập trình Dart và Flutter cơ bản

## 4. Khái niệm State

**State** trong tiếng Anh có nghĩa là trạng thái. Trong thế giới của mobile dev, nó thể hiện các trạng thái của ứng dụng. Mình ví dụ đơn giản nhé. Khi các bạn check / uncheck check box thì đó là hai trạng thái của check box. Ví dụ rõ ràng hơn nữa là màn hình đăng nhập thể hiện ba trạng thái nhập email / mật khẩu sai định dạng (validate error), đăng nhập thành công hoặc đăng nhập fail (api error).

> Nếu các bạn đã từng biết về lập trình mobile với các ngôn ngữ truyền thống như Swift hay Kotlin thì bây giờ chính là lúc chúng ta thay đổi tư duy!

Flutter chuyển đổi cách lập trình truyền thống từ lập trình mệnh lệnh (imperative) sang lập trình khai báo (declarative). Điều này có nghĩa là Flutter UI phản ánh các trạng thái trong app:

![1-8](https://assets.200lab.io/images/2024/12/05/1-8-bebe8db2ed9d02f14b91.webp)

Trong định nghĩa của trang Flutter ở [đây](<https://api.flutter.dev/flutter/widgets/State-class.html>) có nhắc đến, State có thể được đọc một cách đồng bộ khi widget được build và có thể thay đổi trong suốt vòng đời của widget đó.

Vậy thì Stateless Widget và Stateful Widget là gì? Chúng khác nhau ra sao? Chúng ta cùng tìm hiểu tiếp nhé!

## 5. StatelessWidget vs StatefulWidget

### 5.1. StatelessWidget

- **Stateless widget** là các widget có trạng thái không thể thay đổi sau khi chúng được build. Chúng chỉ đơn thuần nhận dữ liệu và hiển thị một cách thụ động. Nếu muốn render lại thì ta phải khởi tạo lại chúng.
- Một ví dụ về stateles widget là _**Text**_. Nó chỉ đơn giản hiển thị các văn bản mà chúng

ta truyền cho nó. Ví dụ khác là _**IconButton**_. Nó chỉ khác Text ở phần là chúng ta có thể tương tác với button nhưng điều đó cũng không làm thay đổi bất cứ điều gì ở button.
- Vòng đời: Vì không thay đổi nên vòng đời của stateless widget khá đơn giản, chỉ xoay quanh hàm [build()](<https://api.flutter.dev/flutter/widgets/State/build.html>).  Câu hỏi được đặt ra ở đây là hàm `build()` của chúng sẽ được gọi khi nào? Mình có thể liệt kê ra những thời điểm như sau:

- Lần đầu tiên widget được khởi tạo và chèn vào trong widget tree. Tìm hiểu thêm về widget tree tại [Flutter cơ bản: Widget Tree, Element Tree và Render Tree](</blog/flutter-co-ban-widget-tree-element-tree-render-tree>).
- Khi widget cha thay đổi cấu hình thì cũng sẽ kích hoạt hàm `build()` của các widget con và khiến chúng được render lại.
- Khi `InheritedWidget` chúng phụ thuộc vào thay đổi. Cái này nghe khá khó hiểu nhỉ? Mình sẽ có một bài viết giải thích cụ thể về InheritedWidget sau nhé!

### 5.2. StatefulWidget

- **Stateful widget** là các widget có thể thay đổi trạng thái. Khác với stateless widget, chúng ta không cần thiết phải khởi tạo lại stateful widget để thay đổi chúng mà chỉ cần thay đổi state của chúng và Flutter sẽ gọi hàm `build()` để render lại UI cho phù hợp với state đó.
- Nghe hơi mơ hồ phải không? Mình ví dụ như nút like của facebook. Khi user bấm like thì nó sẽ đổi thành màu xanh phải không? Và khi user click thêm một lần nữa thì nó chuyển lại màu xám. Đó chính xác là một stateful widget.
- Vòng đời: Vòng đời của Stateful widget thì khá phức tạp, các bạn hãy theo dõi hình sau đây nhé!

![2-6](https://assets.200lab.io/images/2024/12/05/2-6-75c0647696551d779373.webp)

_**Giải thích:**_

- Trước khi đi vào giải thích trên từng con số ở ảnh thì mình muốn mọi người lưu ý một chút. Một statefut widget sẽ bao gồm hai phần là một widget và một state object. Bản thân đối tượng StatefulWidget là **bất biến (immutable)** và lưu trữ trạng thái **có thể thay đổi (mutable)** của chúng trong State object.
- Trên hình mình chia ra làm 3 phần là:

- Time to trigger: thời điểm kích hoạt
- StatefulWidget: phần widget mà mình nhắc đến của StatefulWidget
- State object: phần trạng thái có thể thay đổi được của StatefulWidget
- Bây giờ cùng phân tích những con số trên hình nào!!!

- (1): Thời điểm đầu tiên widget được khởi tạo và chèn vào trong widget tree.
- (2) và (3): Sau khi gọi `constructor`, Flutter sẽ gọi hàm [createState()](<https://api.flutter.dev/flutter/widgets/StatefulWidget/createState.html>) để tạo ra đối tượng của State cho widget. Kể từ đó về sau, Flutter đa số chỉ làm việc State object mà thôi (vì đối tượng của StatefulWidget là bất biến, như mình đã nói ở trên).
- (4): Trên State object, sau khi gọi hàm `createState()` thì hàm [initState()](<https://api.flutter.dev/flutter/widgets/State/initState.html>) sẽ được gọi. Và hàm này chỉ được gọi **chỉ một lần duy nhất** cho mỗi 1 đối tượng của State. Bạn có thể `override` phương thức này để khởi tạo các thuộc tính, khởi tạo dữ liệu, đăng ký Streams, ChangeNotifiers, vân vân và mây mây....
- (5): Phương thức [didChangeDependencies()](<https://docs.flutter.io/flutter/widgets/State/didChangeDependencies.html>) được gọi ngay sau initState lần đầu tiên.
- (6): Hàm `build()` được gọi để render UI. Vậy là hoàn thành các bước kể từ lần đầu tiên widget được khởi tạo. Sau đây sẽ là những bước thực hiện khi có bất kỳ sự thay đổi nào.
- (7): Trường hợp InheritedWidget mà widget có dữ liệu phụ thuộc vào thay đổi thì sẽ kích hoạt hàm `didChangeDependencies()`, sau đó Flutter sẽ gọi  `build()` để render lại UI.
- (8) và (9): Giả sử như user tác động lên UI để thay đổi state của widget (ví dụ như like / unlike) thì khi đó việc của các developer chúng ta sẽ là gọi hàm [setState()](<https://api.flutter.dev/flutter/widgets/State/setState.html>) để thay đổi trạng thái của object. Việc này sẽ giúp cho framework được thông báo về sự thay đổi này và sẽ gọi hàm `build()` để render lại UI tương ứng.
- (10) và (11): Khi widget cha của nó build lại và yêu cầu các widget con build cập nhật lại, Flutter sẽ thực hiện việc gọi hàm [didUpdateWidget()](<https://api.flutter.dev/flutter/widgets/State/didUpdateWidget.html>) . Sau đó, hàm `build()` cũng sẽ được gọi.
- (12): Hàm [dispose()](<https://api.flutter.dev/flutter/widgets/State/dispose.html>) được gọi khi state object bị xoá khỏi widget tree vĩnh viễn.

> Tóm lại, như bạn đã thấy ở trên hàm `build()` là cái hàm được gọi liên tục. Bởi vì sao? Bởi vì nó là nơi quyết định UI, nên khi có bất kỳ sự thay đổi cần thiết nào trên UI, nó sẽ được gọi lại để render tương ứng.

## 6. Cách làm việc với StatlessWidget và StatefulWidget

Ý tưởng của mình như sau:

Đầu tiên mình sẽ tạo một button là StalessWidget, sau đó convert button đó sang StatefulWidget. Mục đích của button này sẽ là like / unlike một cái gì đó giống như nút like trên facebook. Okay! Bắt tay vào thôi nào.

### 6.1. StatelessWidget

Các bạn tạo mới Flutter project và file `like_button.dart` nhé!

#### Bước 1: Tạo mới một StatelessWidget

Trên VS Code, để tạo mới một StalessWidget bạn chỉ cần gõ _stl_ thì trình biên dịch sẽ đề xuất cho bạn

![3-7](https://assets.200lab.io/images/2024/12/05/3-7-5bb6511886783921edf9.webp)

Bạn đặt tên class là `LikeButton` và nhớ import  `package:flutter/material.dart` nhé!

```
import 'package:flutter/material.dart';

class LikeButton extends StatelessWidget {
  const LikeButton({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return IconButton(
        onPressed: () {
          print('Liked');
        },
        iconSize: 20,
        icon: const Icon(Icons.thumb_up_off_alt));
  }
}

```

Action của mình hiện tại chỉ đơn giản là `print`. Vậy là xong phần `LikeButton`. Bạn tiếp tục vào file `main.dart` để sử dụng button này nhé!

#### Bước 2:  Sử dụng StatelessWidget đã tạo ở bước 1

Bạn hãy xoá phần class `MyHomePage` do framework cung cấp sẵn và tự tạo `MyHomePage` của mình. Vẫn là một StatelessWidget nhé!

```
class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('StatelessWidget Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: const [
            LikeButton(),
            Text('You have not like yet!'),
          ],
        ),
      ),
    );
  }
}

```

\*_**Lưu ý nho nhỏ:**_ Ở đây mình có thêm 1 `Text` để thông báo user đã like hay chưa nhé!

Rồi chúng ta cùng build và xem kết quả nhé!

#### Kết quả:

![](https://assets.200lab.io/images/2024/12/05/4-7-0a5640ec3a3355809c51.webp)

Khi ấn nút like thì trên console sẽ log ra cho ta text _"Liked"_.

### 6.2. StatefulWidget

Các bạn có thể dùng lại project trước đó hoặc tạo mới project tương tự như vậy.

![5-7](https://assets.200lab.io/images/2024/12/05/5-7-b02374563ae639a10e0b.webp)

#### Bước 1: Tạo mới một StatefulWidget

Trên VS Code, để tạo mới một StalefulWidget bạn chỉ cần gõ _stf_ thì trình biên dịch sẽ đề xuất cho bạn. Nếu bạn đang sử dụng project trước thì bạn có thể convert `LikeButton` sang StatefulWidget bằng cách di chuyển con trỏ về đầu dòng class LikeButton -\> click vào bóng đèn màu vàng chọn _Convert to StatefulWidget_.

![6-6](https://assets.200lab.io/images/2024/12/05/6-6-84e1a4ed459f5c401209.webp)

Sau khi convert thì `LikeButton` đã trở thành như thế này:

```
class LikeButton extends StatefulWidget {
  const LikeButton({Key? key}) : super(key: key);

  @override
  State<LikeButton> createState() => _LikeButtonState();
}

class _LikeButtonState extends State<LikeButton> {
  @override
  Widget build(BuildContext context) {
    return IconButton(
        onPressed: () {
          print('Liked');
        },
        iconSize: 50,
        icon: const Icon(Icons.thumb_up_off_alt));
  }
}

```

#### Bước 2: Xử lý State object

Để biết được user đã like hay chưa thì mình cần có một biến lưu lại trạng thái này.

```
class _LikeButtonState extends State<LikeButton> {
  // 1
  bool isLiked = false;

  @override
  Widget build(BuildContext context) {
    return IconButton(
        onPressed: () {
          setState(() {
            // 3
            isLiked = !isLiked;
          });
        },
        iconSize: 50,
        // 2
        icon: Icon(isLiked ? Icons.thumb_up_alt : Icons.thumb_up_off_alt));
  }
}

```

_**Giải thích:**_

1. Mình sẽ tạo ra biến `isLiked` kiểu bool với giá trị `true` nghĩa là user đã like và `false` là chưa like. Ở đây mình để giá trị default là false.
2. Thay đổi ảnh của button tương ứng với trạng thái isLiked.
3. Khi user tương tác với button, mình sẽ thực hiện việc đảo trạng thái của biến `isLiked` và thông báo cho framework thông qua việc gọi hàm `setState()`

Vậy là xong! Chúng ta cùng build lên xem kết quả nhé! Hiện tại, mình vẫn giữ `MyHomePage` giống như phần StatelessWidget nha!

![](https://assets.200lab.io/images/2024/12/05/7-0bd25c80d54276316250.webp)

Các bạn có để ý thấy phần `Text` ở dưới vẫn chưa khớp với trạng thái của button không? Đây là lúc chúng ta sẽ biến `MyHomePage` thành một StatefulWidget luôn!

#### Bước 3: Chuyển đổi MyHomePage thành StatefulWidget.

Tương tự như mình đã nhắc ở bước 1, các bạn có thể convert `MyHomePage` thành StatefulWidget bằng cách di chuyển con trỏ về đầu dòng class `MyHomePage` -\> click vào bóng đèn màu vàng chọn _Convert to StatefulWidget_.

Tiếp theo, các bạn quay trở lại class `LikeButton` để thêm callback về nhằm thông báo cho `MyHomePage` biết trạng thái `isLiked`

```
import 'package:flutter/material.dart';

class LikeButton extends StatefulWidget {
  // 1
  final Function(bool) didTapButton;
  // 2
  const LikeButton(this.didTapButton, {Key? key}) : super(key: key);

  @override
  State<LikeButton> createState() => _LikeButtonState();
}

class _LikeButtonState extends State<LikeButton> {
  bool isLiked = false;

  @override
  Widget build(BuildContext context) {
    return IconButton(
        onPressed: () {
          setState(() {
            isLiked = !isLiked;
            // 3
            widget.didTapButton(isLiked);
          });
        },
        iconSize: 50,
        icon: Icon(isLiked ? Icons.thumb_up_alt : Icons.thumb_up_off_alt));
  }
}

```

_**Giải thích:**_

1. `didTapButton` là 1 biến kiểu function và trả về kiểu `bool`. Biến được khai báo là final vì nó sẽ không thay đổi.
2. Tạo constructor để init biến `didTapButton`.
3. Sau khi `isLiked` được đảo trạng thái, chúng ta đồng thời callback trạng thái này ra để `MyHomePage` nhận biết sự thay đổi.

Sau khi sửa lại LikeButton, bạn quay lại MyHomePage và tiếp tục xử lý phần thay đổi Text:

```
class _MyHomePageState extends State<MyHomePage> {
  // 1
  String likedStatusText = 'You have not like yet!';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('StatefulWidget Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            // 3
            LikeButton((isLiked) {
              // 4
              setState(() {
                likedStatusText =
                  isLiked ? 'You liked!' : 'You have not like yet!';
              });
            }),
            // 2
            Text(likedStatusText),
          ],
        ),
      ),
    );
  }
}

```

_**Giải thích:**_

1. Khai báo biến kiểu `String` trong State object của `MyHomePage`. Đây sẽ là nơi nhận sự thay đổi text.
2. Lúc này `Text` sẽ sử dụng biến state chúng ta vừa tạo thay vì text set cứng như lúc đầu.
3. Truyền vào đối số cho callback function của `LikeButton`.
4. Khi nhận được callback trả về state của `LikeButton` thì `MyHomePage` sẽ gọi hàm `setState()` để set text tương ứng cho `likedStatusText` từ đó kích hoạt Flutter render lại UI.

#### Kết quả

![](https://assets.200lab.io/images/2024/12/05/8-e8b09745865527756ad0.webp)

#### [Demo source code](<https://github.com/vanle57/stateless-stateful-widget/tree/main/demo%20source%20code>)

## 7. Tổng kết

Tóm lại sự khác nhau rõ rệt và có thể dễ dàng thấy được nhất giữa StalessWidget và StatefulWidget chính là khả năng reload của widget ở runtime. Nếu như StalessWidget không thể thay đổi chỉ trừ khi được khởi tạo lại thì StatefulWidget có các trạng thái có thể thay đổi được và Flutter sẽ render lại UI cho phù hợp với từng trạng thái.

Bài viết cũng khá dài nên mình xin tạm gác bút lại ở đây. Hẹn gặp các bạn vào các bài viết tiếp theo của mình nhé!

#### Tài liệu tham khảo

- [StatelessWidget class - widgets library - Dart API](<https://api.flutter.dev/flutter/widgets/StatelessWidget-class.html>)
- [StatefulWidget class - widgets library - Dart API](<https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html>)
- [StatelessWidget và StatefulWidget trong Flutter - Blog Lập Trình](<https://bloglaptrinh.info/statelesswidget-va-statefulwidget-trong-flutter>)
- [Flutter rules the World: Widget, Stateful Widget and Stateless Widget! - TMA Solutions](<https://www.tma.vn/Hoi-dap/Cam-nang-nghe-nghiep/Flutter-rules-the-World-Widget-Stateful-Widget-and-Stateless-Widget/57102>)
- [Flutter cơ bản: State trong Flutter](</blog/flutter-co-ban-state-trong-flutter>)
