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 ý:
- Dữ liệu được widget sử dụng và có thể thay đổi.
- 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

Mục lục
Tại sao lại cần StatefulWidget và State Classes riêng biệt?
Đó là vì performance.
Vì State
khô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 state
S 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ì State
khô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 để:
- Khởi tạo dữ liệu dựa trên BuildContext cho widget đã được tạo.
- Khởi tạo các thuộc tính dựa vào widget parent trong tree.
- Đă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 Widget
liê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 setState
là 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 context
sẽ đượ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 State
bị 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 .