Home Coding StatefulWidget lifecycle

StatefulWidget lifecycle

by Khanh Tran

Khi Flutter build một StatefulWidget, nó sẽ tạo ra một State object. Object này là nơi chứa tất cả mutable state cho widget đó. Trong phần này, chúng ta cùng tìm hiểu về StatefulWidget lifecycle.

Trong bài trước chúng ta đã biết State được định nghĩa qua 2 ý:

  1. Dữ liệu được widget sử dụng và có thể thay đổi.
  2. Dữ liệu không thể đọc đồng bộ dữ liệu khi widget được build. (Tất cả state phải được thiết lập vào thời điểm phương thức build được gọi).

StatefulWidget lifecycle gồm các bước sau:

  • createState()
  • mounted == true
  • initState()
  • didChangeDependencies()
  • build()
  • didUpdateWidget()
  • setState()
  • deactivate()
  • dispose()
  • mounted == false
Hình 1: StatefulWidget lifecycle.

Tại sao lại cần StatefulWidget và State Classes riêng biệt?

Đó là vì performance.

Vì Statekhông bị xoá đi trong mỗi lần rebuild, nó tránh được các tính toán dư thừa và nhận được stateS property, getters, setters, v.v. mỗi khi có thứ gì đó được rebuilt frame by frame.

Quan trọng là đây là thứ cho phép các Flutter animations tồn tại. Vì Statekhông bị huỷ bỏ, nó có thể liên tục rebuild rebuild Widgetđể đáp ứng với các thay đổi dữ liệu khi được yêu cầu.

createState()

Khi Flutter build một StatefulWidget, nó ngay lập tức sẽ gọi createState(). Phương pháp bắt buộc phải có. Một StatefulWidget hiếm khi cần phức tạp hơn thế này, nghĩa là phần lớn các StatefulWidget chúng ta sử dụng chỉ cần dùng phương thức createState()

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

mounted is true

Khi createState creates một state class, một buildContext sẽ được gán cho state đó.

BuildContext, định nghĩa đơn giản nhất thì nó xác định và điều khiển vị trí của một widget trong cây widget..

Tất cả các Widgets đều có một thuộc tính bool this.mounted. Nó sẽ trả về true khi buildContext được gán, và sẽ là một error khi gọi setstate của một widget bị ngắt kết nối.

Tip: Bạn nên sử dụng if (mounted) {… } để đảm bảo State tồn tại trước khi gọi setState ().

initState()

Đây là phương thức đầu tiên được gọi khi widget được tạo (tất nhiên là sau hàm constructor).

initStateđược gọi một và chỉ một lần, kèm theo đó làsuper.initState().

@override method là nơi tốt nhất để:

  1. Khởi tạo dữ liệu dựa trên BuildContext cho widget đã được tạo.
  2. Khởi tạo các thuộc tính dựa vào widget parent trong tree.
  3. Đăng ký Streams, ChangeNotifiers, hoặc bất kỳ đối tượng nào khác có thể thay đổi dữ liệu trên widget này.
@override
initState() {
  super.initState();
  // Add listeners to this class
  cartItemStream.listen((data) {
    _updateWidget(data);
  });
}

didChangeDependencies()

Phương thức didChangeDependencies được gọi ngay sau initState cho lần đầu tiên widget được build trong một StatefulWidget lifecycle.

Nó cũng sẽ được gọi bất cứ khi nào một object mà widget này phụ thuộc vào dữ liệu từ nó được gọi. Ví dụ: nếu nó dựa vào một InheritedWidget, InheritedWidget sẽ được cập nhật.

Phương thứcbuild luôn được gọi sau khi didChangeDependenciesđược gọi. Tuy nhiên, để phương thức này thay đổi đầu tiên bạn phải gọi BuildContext.inheritFromWidgetOfExactType. Điều này về cơ bản sẽ làm cho State này ‘lắng nghe’ các thay đổi trên một Widget mà nó kế thừa dữ liệu.

Docs chính thức của Flutter cũng gợi ý rằng nó có thể hữu ích nếu bạn cần thực hiện các cuộc gọi network khi InheritedWidget cập nhật.

build()

Phương thức này được gọi để render một widget. Bắt buộc phải @override và return một Widget.

didUpdateWidget(Widget oldWidget)

trong một StatefulWidget lifecycle, didUpdateWidget()được gọi nếu widget cha thay đổi và phải rebuild widget này (vì nó cần cung cấp cho nó dữ liệu khác), nhưng nó đang được rebuild với cùng một runtimeType, thì lúc đó phương thức này được gọi.

Điều này là do Flutter đang sử dụng lại state, cái mà đã tồn tại từ trước. Trong trường hợp này, yêu cầu là khởi tạo lại một số dữ liệu, giống như khi sử dụng initState().

Nếu phương thức build() của state dựa vào một Stream hoặc object khác có thể thay đổi, hãy hủy đăng ký khỏi object cũ và đăng ký lại object mới trong didUpdateWidget().

Tip: Phương thức này về cơ bản là sự thay thế cho ‘initState ()’ nếu nó được mong đợi rằng Widgetliên kết với state của widget cha sẽ được rebuild!

Flutter luôn gọi build()sau điều này, vì vậy bất kỳ phương thức build nào tiếp theo setStatelà dư thừa.

@override
void didUpdateWidget(Widget oldWidget) {
  if (oldWidget.importantProperty != widget.importantProperty) {
    _init();
  }
}

setState ()

Phương thức ‘setState ()’ thường được gọi từ chính Flutter framework và từ developer.

Nó được sử dụng để thông báo cho framework rằng dữ liệu đã thay đổi và widget tại build contextsẽ được rebuild.

void updateProfile(String name) {
 setState(() => this.name = name);
}

deactivate()

Phương thức này hiếm khi được sử dụng.

‘deactivate ()’ được gọi khi Statebị xóa khỏi tree, nhưng nó có thể được xác nhận lại trước khi quá trình xoá kết thúc. Phương thức này tồn tại về cơ bản vì State có thể được di chuyển từ điểm này sang điểm khác trên một tree.

dispose()

‘dispose ()’ được gọi khi State bị removed vĩnh viễn.

Phương thức này là nơi để hủy đăng ký và cancel tất cả các animations, streams, vv…

mounted is false

Khi đối tượng state không bao giờ có thể remount và khi bạn gọi setState() sẽ có lỗi .

You may also like

Leave a Comment