+3

StatelessWidget và StatefulWidget trong Flutter

Giới thiệu

Mọi thứ bạn nhìn thấy trên màn hình của ứng dụng được xây dựng bằng Flutter đều là Widget. Ví dụ: các nút, hình ảnh, hộp cảnh báo, thanh ứng dụng, v.v., tất cả đều là các widget trong Flutter và với sự trợ giúp của các widget này, bạn có thể xây dựng một ứng dụng đơn giản hơn như Calculator app cho đến các ứng dụng phức tạp và tương tác hơn như ứng dụng Instagram.

Các Widget này được chia thành hai loại, tức là StatelessWidgetStatefulWidget. Trong bài viết này, chúng ta sẽ cùng tìm hiểu về sự khác biệt giữa 2 loại Widget này.

Điểm giống nhau

Có rất nhiều thứ hiện diện trên bàn làm việc của bạn như máy tính xách tay, màn hình, chậu hoa, chai nước, v.v. Nếu bạn để nguyên tất cả các vật dụng có trên bàn làm việc thì bạn sẽ không thay đổi trạng thái của bàn làm việc. Nhưng một ngày nào đó, bạn cho rằng vị trí của chậu hoa không đúng. Vì vậy, bạn đã thay đổi vị trí của cái chậu. Ở đây, bạn đã thay đổi trạng thái của chậu hoa, tức là có sự thay đổi về vị trí ban đầu và cuối cùng hoặc trạng thái của chậu hoa.

Điều tương tự cũng xảy ra trong trường hợp của các ứng dụng. Trong bất kỳ ứng dụng di động nào, có một số Widget sẽ không thay đổi và có bản chất tĩnh. Ví dụ: thông tin liên hệ có trong bất kỳ ứng dụng nào vẫn giữ nguyên, tức là tên của nhà phát triển sẽ không thay đổi trong suốt thời gian tồn tại của ứng dụng. Vì vậy, bạn sử dụng một widget Text để hiển thị thông tin liên hệ và Text này không thay đổi trạng thái khi chạy.

Nhưng có một số trường hợp nhất định trong đó Widget có bản chất động, tức là chúng liên tục thay đổi khi người dùng tương tác với Widget. Ví dụ: bất cứ khi nào bạn thích một số bài đăng trên Instagram, thì text hiển thị số lượt thích sẽ tăng thêm 1 và màu của nút thích cũng chuyển sang màu đỏ. Vì vậy, ở đây cả ImageText đều có tính chất động và đang thay đổi trạng thái khi chạy.

Vì vậy, dựa trên khả năng reload của các widget trong thời gian chạy, các Widget được chia thành hai loại:

  • StatelessWidget
  • StatefulWidget

Hình ảnh đầu tiên là một loại trang liên hệ nơi có nhiều thông tin tĩnh khác nhau như logo công ty, trang web, v.v. Trạng thái của Widget là cố định và về bản chất chúng là Stateless. Nhưng hình ảnh thứ hai là từ Twitter. Tại đây số lượng Người theo dõi hoặc số Người theo dõi sẽ thay đổi. Vì vậy, trạng thái của Văn bản đại diện cho những con số này không có trạng thái cố định. Chúng có bản chất là Stateful.

Hãy cùng tìm hiểu thêm về hai loại Widget này bằng cách tìm hiểu sâu hơn về nó.

StatelessWidget

StatelessWidgets được sử dụng khi một phần của giao diện người dùng không thay đổi linh hoạt, tức là chúng ta chỉ có nội dung tĩnh và không thể thay đổi.

Để tạo một Widget không trạng thái, bạn cần mở rộng lớp của mình từ StatelessWidget và bạn cũng cần ghi đè phương thức build sẽ trả về một hoặc nhiều tiện ích. Sau đây là một ví dụ về StatelessWidget :

class MyApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
   return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Example'),
          backgroundColor: Colors.blueGrey[900],
        ),
        backgroundColor: Colors.white,
        body: Container(),
      ),
    );
  }
}

Đoạn code trên là một ví dụ về StatelessWidget trong đó MyApp là StatelessWidget và nó ghi đè method build. Method build đang trả về một tiện ích MaterialApp và method này sẽ chỉ được gọi một lần, tức là bất cứ khi nào MyApp được khởi tạo thì bản build sẽ được gọi và các widget sẽ được vẽ trên màn hình.

Nhưng nếu có sự thay đổi trong bất kỳ biến nào liên quan đến Widget thì phương thức xây dựng sẽ không được gọi và sẽ không có gì được cập nhật trên màn hình vì đó là StatelessWidget.

Để thay đổi trạng thái của Widget dựa trên trạng thái của các biến liên quan đến Widget, chúng ta sử dụng StatefulWidgets.

StatefulWidget

StatefulWidget được sử dụng khi một phần của giao diện người dùng thay đổi linh hoạt, tức là khi chúng ta có các widget có thể thay đổi thì chúng ta sử dụng StatefulWidget.

Để tạo Stateful Widget, bạn cần mở rộng class của mình từ StatefulWidget và ở đây thay vì ghi đè phương thức xây dựng, bạn cần ghi đè phương thức createState(). Phương thức createState() trả về một đối tượng State. Sau đó, chúng ta tạo một lớp khác được mở rộng từ State và ở đây trong lớp này, chúng ta cần ghi đè phương thức build và phương thức build này sẽ trả về một hoặc nhiều widget. Sau đây là một ví dụ về StatefulWidget :

class MyApp extends StatefulWidget {
 @override
 _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
 @override
 Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Example'),
          backgroundColor: Colors.blueGrey[900],
        ),
        backgroundColor: Colors.white,
        body: Container(),
      ),
    );
  }
}

Trong ví dụ trên, MyApp là StatefulWidget và nó ghi đè phương thức createState(). Phương thức này trả về phiên bản của lớp MyAppState và bên trong lớp này, chúng ta đang ghi đè phương thức xây dựng.

Vì vậy, ưu điểm của việc ghi đè phương thức build trong MyAppState là giờ đây phương thức build sẽ được gọi bất cứ khi nào có sự thay đổi trong các biến liên kết với các Widget có trong đó và toàn bộ tiện ích sẽ được vẽ lại một lần nữa. Nhưng để gọi phương thức build, bạn cần thêm một phương thức khác gọi là setState() phương thức này sẽ gọi phương thức build bất cứ khi nào có thay đổi về trạng thái.

Hãy tìm hiểu thêm với sự giúp đỡ của một ví dụ.

Example

Trong ví dụ này, chúng ta sẽ tạo một ứng dụng đơn giản có chứa một biểu tượng Yêu thích và biểu tượng này sẽ thay đổi màu từ đen sang đỏ và lại đỏ sang đen bất cứ khi nào bạn nhấn vào biểu tượng.

Sau đây là cây widget cho ứng dụng này: Đầu tiên, chúng ta sẽ bắt đầu với StatelessWidget. Trong tệp main.dart, nhập stless và nhấn enter để tạo tiện ích không trạng thái và đặt tên là MyApp .

Trong MyApp, ngoài các widget, chúng ta sẽ có một hàm ChangeColor sẽ thay đổi màu của biểu tượng khi được nhấn và nó sẽ tăng biến bộ đếm lên 1. Sau đây là mã cho tệp main.dart:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  int counter = 0;
  Color buttonColor = Colors.black;

  void changeColor() {
    counter++;
    if (buttonColor == Colors.black) {
      buttonColor = Colors.red;
    } else {
      buttonColor = Colors.black;
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Example'),
          backgroundColor: Colors.blueGrey[900],
        ),
        backgroundColor: Colors.white,
        body: SafeArea(
          child: Center(
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                FlatButton(
                  child: Icon(
                    Icons.favorite,
                    color: buttonColor,
                    size: 80.0,
                  ),
                  onPressed: () {
                    changeColor();
                    print(counter);
                  },
                ),
                Text('Cliked Count: $counter'),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Bây giờ, hãy chạy ứng dụng và nhấn vào biểu tượng. Bạn có thấy bất kỳ thay đổi nào về màu sắc của biểu tượng không? Không. Bạn sẽ không thấy bất kỳ thay đổi nào về màu sắc hoặc giá trị của văn bản biểu thị số lần nhấn biểu tượng. Giá trị của biến đếm có đang cập nhật hay không? Hãy xem nào.

Trong phương thức onPressed, chúng tôi đã in giá trị của biến bộ đếm, vì vậy khi nhấn biểu tượng, bạn có thể thấy sự thay đổi về giá trị của biến bộ đếm trong Bảng điều khiển gỡ lỗi.

Bạn cũng có thể thấy giá trị đã thay đổi của biến đếm bằng cách Tải lại ứng dụng. Khi bạn Hot Reloading, bạn sẽ thấy giá trị cập nhật của biến bộ đếm trên màn hình. Một lần nữa, nếu bạn nhấn vào biểu tượng thì sẽ không có gì thay đổi. Vậy thì chuyện gì đã xảy ra ở đây?

Vì đoạn code trên là Stateless nên phương thức build chỉ được gọi một lần và thậm chí sau khi gọi phương thức ChangeColor từ phương thức onPressed, biến bộ đếm đang tăng nhưng nó không được hiển thị trên màn hình vì để làm được điều đó, bạn cần gọi phương thức xây dựng bất cứ khi nào giá trị của bộ đếm thay đổi. Bây giờ, khi bạn Hot Reload ứng dụng thì phương thức xây dựng sẽ được gọi và giá trị cập nhật của biến bộ đếm sẽ được hiển thị. Một lần nữa, nếu bạn nhấn vào biểu tượng thì sẽ không có gì thay đổi vì phương thức xây dựng sẽ không được gọi lại.

Vậy làm cách nào để khắc phục vấn đề trên, tức là làm cách nào để thay đổi màu của biểu tượng và cập nhật giá trị của văn bản khi chạy?

Vâng, rõ ràng là chúng ta sẽ sử dụng StatefulWidget cho mục đích tương tự vì đây là trường hợp sử dụng của chúng ta. Ở đây, khi nhấn vào biểu tượng, màu sắc của biểu tượng và văn bản sẽ thay đổi.

Tạo StatefulWidget bằng cách nhập stful và nhấn enter. Đặt tên là MyApp . Mã cho tệp main.dart sẽ trông giống như bên dưới:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int counter = 0;
  Color buttonColor = Colors.black;
  void changeColor() {
    counter++;
    if (buttonColor == Colors.black) {
      buttonColor = Colors.red;
    } else {
      buttonColor = Colors.black;
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Example'),
          backgroundColor: Colors.blueGrey[900],
        ),
        backgroundColor: Colors.white,
        body: SafeArea(
          child: Center(
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                FlatButton(
                  child: Icon(
                    Icons.favorite,
                    color: buttonColor,
                    size: 80.0,
                  ),
                  onPressed: () {
                    setState(() {
                      changeColor();
                      print(counter);
                    });
                  },
                ),
                Text('Cliked Count: $counter'),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Bây giờ, hãy chạy ứng dụng và nhấn vào biểu tượng Yêu thích. Bạn sẽ thấy sự thay đổi về màu sắc cũng như sự gia tăng của biến đếm.

Nếu nhìn kỹ vào code thì bạn sẽ thấy code này gần giống với code Stateless ở trên, điểm khác biệt duy nhất là ở đây trong phương thức onPressed, chúng tôi đã giới thiệu thêm một phương thức nữa gọi là setState . Phương thức setState này sẽ được gọi bất cứ khi nào bạn nhấn vào biểu tượng và nhiệm vụ của phương thức setState là gọi đi gọi lại hàm build để hiển thị các thay đổi trên màn hình.

Sau đây là đầu ra của ứng dụng của chúng ta:

Kết luận

Vì vậy, theo cách này, bạn có thể sử dụng các widget Stateless hoặc Stateful tùy theo trường hợp sử dụng của mình. Nếu bạn có thứ gì đó trên màn hình sẽ thay đổi bất cứ khi nào người dùng tương tác với ứng dụng thì bạn cần sử dụng StatefulWidget . Ngược lại, nếu nội dung trên màn hình là tĩnh thì bạn có thể sử dụng StatelessWidget .

Cảm ơn các bạn đã đọc tới đây, và chúc một ngày tốt lành 😄

Nguồn tham khảo: https://blog.mindorks.com/statelesswidget-vs-statefulwidget-in-flutter/


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.