Các xây dựng phương pháp được thiết kế theo cách như vậy mà nó nên tinh khiết / không có tác dụng phụ . Điều này là do nhiều yếu tố bên ngoài có thể kích hoạt một bản dựng widget mới, chẳng hạn như:
- Tuyến pop / đẩy
- Thay đổi kích thước màn hình, thường là do sự xuất hiện của bàn phím hoặc thay đổi hướng
- Phụ huynh đã tạo lại con của nó
- Một kế thừaWidget tiện ích phụ thuộc vào
Class.of(context)
thay đổi ( mẫu)
Điều này có nghĩa là build
phương thức không được kích hoạt cuộc gọi http hoặc sửa đổi bất kỳ trạng thái nào .
Làm thế nào điều này có liên quan đến câu hỏi?
Vấn đề bạn đang gặp phải là phương pháp xây dựng của bạn có tác dụng phụ / không thuần túy, khiến cuộc gọi xây dựng bên ngoài trở nên rắc rối.
Thay vì ngăn chặn cuộc gọi xây dựng, bạn nên làm cho phương thức xây dựng của mình thuần túy, để nó có thể được gọi bất cứ lúc nào mà không bị ảnh hưởng.
Trong trường hợp ví dụ của bạn, bạn sẽ chuyển đổi widget của mình thành một StatefulWidget
cuộc gọi HTTP sau đó đến cuộc gọi initState
của bạn State
:
class Example extends StatefulWidget {
@override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
Future<int> future;
@override
void initState() {
future = Future.value(42);
super.initState();
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: future,
builder: (context, snapshot) {
// create some layout here
},
);
}
}
Tôi biết điều này rồi. Tôi đến đây vì tôi thực sự muốn tối ưu hóa việc xây dựng lại
Cũng có thể tạo ra một vật dụng có khả năng xây dựng lại mà không buộc con cái của nó phải xây dựng quá.
Khi thể hiện của một widget vẫn như cũ; Flutter cố tình sẽ không xây dựng lại trẻ em. Nó ngụ ý rằng bạn có thể lưu trữ các phần của cây widget để ngăn chặn việc xây dựng lại không cần thiết.
Cách dễ nhất là sử dụng các hàm tạo phi tiêu const
:
@override
Widget build(BuildContext context) {
return const DecoratedBox(
decoration: BoxDecoration(),
child: Text("Hello World"),
);
}
Nhờ const
từ khóa đó , ví dụ DecoratedBox
sẽ giữ nguyên ngay cả khi bản dựng được gọi hàng trăm lần.
Nhưng bạn có thể đạt được kết quả tương tự bằng tay:
@override
Widget build(BuildContext context) {
final subtree = MyWidget(
child: Text("Hello World")
);
return StreamBuilder<String>(
stream: stream,
initialData: "Foo",
builder: (context, snapshot) {
return Column(
children: <Widget>[
Text(snapshot.data),
subtree,
],
);
},
);
}
Trong ví dụ này khi StreamBuilder được thông báo về các giá trị mới, subtree
sẽ không xây dựng lại ngay cả khi StreamBuilder / Cột thực hiện. Điều đó xảy ra bởi vì, nhờ việc đóng cửa, trường hợp MyWidget
không thay đổi.
Mẫu này được sử dụng rất nhiều trong hình ảnh động. Sử dụng điển hình là AnimatedBuilder
và tất cả các chuyển tiếp như AlignTransition
.
Bạn cũng có thể lưu trữ subtree
vào một trường trong lớp của mình, mặc dù ít được khuyến nghị hơn vì nó phá vỡ tính năng tải lại nóng.