+4

StatefulWidget và StatelessWidget trong Flutter

I. Mở đầu

Khi các bạn build một ứng dụng với Flutter thì Widgets là thứ không thể thiếu đúng không ạ. Và 2 loại Widget không thể thiếu đó là StatefullWidget và StatelessWidget. Trong bài này mình sẽ chia sẻ với các bạn và 2 loại Widget này nhé ! 😀

II. Chi tiết

1. Widgets

  • Widget chính là nền tảng của Flutter, một widget miêu tả một phần của giao diện người dùng. Tất cả các component như text, image, button hay animation, theme, layout hay thậm chí app cũng là 1 widget. Trong Flutter tất cả các widget hay giao diện đều được code bằng dart

  • Khi một widget thay đổi trạng thái, chẳng hạn như do người dùng click hay animation, widget sẽ tự xây dựng lại theo trạng thái mới. Điều này tiết kiệm thời gian của nhà phát triển bởi vì UI có thể được mô tả như là một state functions. Ta không phải viết thêm code để chỉ update UI khi state change.
  • Widget đơn giản là những class. Ví dụ: class Text. À ra là như vậy, nếu liên kết những yếu tố này lại ta có thể hình dung một class Widget có những property lưu trữ và thể hiện những thông tin của Widget như thế này:
class Text { // Widget chỉ là class
    String text; // các property lưu trữ thông tin của widget
    Color textColor; // thông tin về màu sắc của text
    int fontSize; // thông tin về kích cỡ của font
}

2. Build function

Bạn có biết công thức toán học quen thuộc y = f(x). Đó là một hàm số, khi ta có giá trị của x, dựa vào một function f ta sẽ tính được giá trị y. Bất cứ khi nào x thay đổi thì cũng cho ta một giá trị mới của y đúng ko. Flutter cũng tương tự như vậy, nó sử dụng công thức là:

UI = f(Data)

Khi Data của Widget thay đổi, UI sẽ được update theo công thức hàm f. Các bạn thấy khi mình click vào button màu xanh đó thì UI được thay đổi hiển thị con số khác đúng ko. Con số 0, 1, 2, 3, ... đó chính là Data của Widget. Data đó được lưu trữ trong một biến có kiểu int. Khi Data thay đổi nó sẽ thay đổi UI theo công thức hàm f.

Như vậy, chúng ta đã hình dung được Data của Widget và hàm build và mối quan hệ UI = build(Data). Đây chính là nguyên tắc hoạt động của Flutter. Chúng ta sẽ đi đến định nghĩa kế tiếp về State.

3. State là gì

Giả sử như bây giờ, bạn tự tạo ra một cái Widget là cái bóng đèn đi. Cái bóng đèn sẽ có những thông tin nào nhỉ:

  1. Kích cỡ (size) của bóng đèn có kiểu int. Thông tin này không bao giờ thay đổi. Ví dụ cái bóng đèn khi sản xuất có size 20 chẳng hạn, thì 10 năm sau cũng sẽ có size 20 chứ nó không thể to ra hay nhỏ lại theo năm tháng được, trừ khi nó bị đập phá (Widget die) =))
  2. Màu sắc đang hiển thị đèn kiểu Color, màu bóng đèn default sẽ là yellow, nhưng có lúc sẽ đổi thành red, lúc thì blue. Đây là một thông tin có thể thay đổi, cứ một vài milisecond thì nó sẽ thay đổi một lần. Nếu màu đèn nó không thay đổi thì có thể là bị hư (Widget die) =))

Như vậy class được mình đặt tên là BulbLightWidget này có 2 property là size (kích cỡ của bóng đèn) và currenLight (màu của bóng đèn hiện tại). Biến size có 1 giá trị mãi mãi không thay đổi nên sẽ khai báo final height, biến currentLight có thể thay đổi được bằng cách gán lại giá trị mới nên khai báo var currentLight hoặc Color currentLight.

class BulbLightWidget {
  final size = 20; // height này cố định ko thay đổi nên để final
  Color currentLight = Colors.red; // màu đèn sẽ thay đổi từ đỏ, vàng, xanh
}

Như vậy, có thể phân chia data của Widget thành 2 loại: Thông tin có thể thay đổi và thông tin không thể thay đổi.

Còn đây là định nghĩa đơn giản, ngắn gọn nhất về State:

State là thông tin thể hiện trên Widget mà có thể thay đổi trong suốt thời gian sống sót trên đời của Widget

Trong cái widget bóng đèn đó thì cái data currentLight đó chính là state vì nó thay đổi được. Khi nó thay đổi thì widget BulbLightWidget phải build lại giao diện khác. Ví dụ currentLight = Colors.red thì widget hiển thị đèn đỏ. Khi currentLight thay đổi thành currentLight = Colors.green thì widget phải build lại để hiển thị đèn xanh. Còn cái size chỉ là data bình thường, không phải là state vì nó luôn không đổi, cái bóng đèn sẽ mãi mãi to chừng đó.

Okay, mình đã hiểu có Data, có công thức là hàm build thì mình sẽ xây được UI. Khi Data thay đổi, hàm build sẽ được gọi lại để update UI (chúng ta gọi đây là rebuild Widget). Có 2 loại widget là StatefulWidgetStatelessWidget, loại nào cũng có hàm build nhưng cách chúng gọi hàm build để update UI là khác nhau:

Một là: StatefulWidget, bản thân Widget này sẽ chủ động update UI. Hai là: StatelessWidget, bản thân Widget này sẽ thụ động update UI, hay nói cách khác là bị Widget khác ép phải update UI. Như thế nào là chủ động, như thế nào là bị ép. Chúng ta sẽ đến với cách đầu tiên, chủ động update UI sử dụng StatefulWidget.

4. StatelessWidget

Stateless widget không có state. Nó không chấp nhận sự thay đổi bên trong nó. Còn đối với sự thay đổi từ bên ngoài (widget cha) thì nó sẽ thụ động thay đổi theo.

Có nghĩa là StatelessWidget chỉ đơn thuần nhận dữ liệu và hiển thị 1 cách thụ động. Việc tương tác với nó không sinh ra bất kỳ một event nào để chính bản thân phải render lại. Nếu phải render lại thì là do tác động từ bên ngoài vào.

Vậy nên, nó không có liên quan gì đến State cả. Bản thân nó cũng không có hàm createState mà thay vào đó là hàm build(BuildContext)

Ví dụ: ta có thể nhìn 1 vài mẫu Stateless widgets.

Xét loại Text widget là để khởi tạo trong một constructor và những properties thường để build widget và hiển thị lên màn hình

5. StatefullWidget

StatefulWidget là chỉ đơn giản là một Widget mà CÓ State tức là nó có data có thể thay đổi được. Khi state thay đổi, nó sẽ gọi lại hàm build để rebuild widget. Nhờ đó mà UI thay đổi.

Đây là cấu tạo của một StatefulWidget:

class BulbLightWidget extends StatefulWidget { // 1
  final size = 20; // mọi data trong class Widget phải immutable
  // data nào mutable xin mời qua class khác, là class State bên dưới :D

  // khi StatefulWidget được khởi tạo nó sẽ gọi hàm createState để tạo 1 object State
  @override
  State<StatefulWidget> createState() {
    return BulbLightState();
  }
}

// khi object Widget gọi hàm createState thì object State ra đời
class BulbLightState extends State<BulbLightWidget> { // 2
  var currentLight = 'đỏ';

  // hàm build
  @override
  Widget build(BuildContext context) {
    return Text('Kích thước đèn ${widget.size} và đèn đang có màu $currentLight'); // 3
  }
}

Ban đầu khi khởi tạo StatefulWidget, hàm build đã được gọi một lần đầu tiên, và nó nhận default state để update UI: UI = build(default state). Mỗi lần chúng ta gọi hàm setState thì nó sẽ gọi lại hàm build để update UI mới: UI = build(new state)

Demo StatefullWidget

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

// Đây là một StatefulWidget
class MyHomePage extends StatefulWidget {
  @override
  MyHomePageState createState() => MyHomePageState();
}

// Đây là class State của StatefulWidget MyHomePage
class MyHomePageState extends State<MyHomePage> {
  int counter = 0; // Data của Widget

  @override
  Widget build(BuildContext context) { // hàm build
    return Scaffold(
      body: Center(
        // data là biến counter được truyền vào hàm build - công thức UI = build(Data)
        child: Text('Tui là widget Text. Data của tui hiện tại là: $counter')
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () { // khi click button màu xanh blue
          setState(() { // ta sẽ gọi hàm setState
            counter++; // để gán lại giá trị mới cho biến counter
            // bên trong hàm setState này sẽ tự động gọi lại hàm build nên UI được update (rebuild)
          });
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

Đây là thành quả:

III. Tổng kết lại kiến thức

Đây là những kiến thức quan trọng trong bài, mình sẽ tổng kết ngắn gọn lại như sau:

  1. Scene = f(Data) trong đó f là hàm build có trong mỗi StatelessWidget hay StatefulWidget. Flutter hoạt động theo công thức đó: Khi thay đổi Data thì UI sẽ được update.
  2. State chính là Mutable data của widget nên State là data của Widget mà có thể thay đổi được.
  3. StatefulWidget là widget có State, còn StatelessWidget là widget không có State.
  4. StatefulWidget có thể chủ động update UI bằng cách gọi hàm setState.
  5. Data trong StatelessWidget không thể thay đổi được nên nó muốn update được UI thì phải nhờ thằng cha là một StatefulWidget nào đó có khả năng thay đổi data giúp nó rồi truyền data xuống cho nó thông qua constructor.
  6. Mọi data trong class StatefulWidgetStatelessWidget đều phải là immutable
  7. Hãy sử dụng StatelessWidget hết mức có thể - các đồng nghiệp sẽ yêu mến bạn.

Tài liệu tham khảo

  1. https://flutterdoc.com/stateful-or-stateless-widgets-42a132e529ed
  2. http://eitguide.net/flutter-bai-7-state-va-stateful-stateless-widgets/
  3. https://flutter.dev/docs/development/data-and-backend/state-mgmt/intro
  4. https://medium.com/@agungsurya/basic-state-management-in-google-flutter-6ee73608f96d

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí