สร้างวิธีการออกแบบในลักษณะดังกล่าวว่ามันควรจะเป็น/ บริสุทธิ์ไม่มีผลข้างเคียง เนื่องจากปัจจัยภายนอกหลายอย่างสามารถทริกเกอร์การสร้างวิดเจ็ตใหม่เช่น:
- เส้นทางป๊อป / พุช
- การปรับขนาดหน้าจอมักเกิดจากลักษณะแป้นพิมพ์หรือการเปลี่ยนทิศทาง
- วิดเจ็ตหลักสร้างลูกใหม่
- InheritedWidget วิดเจ็ตขึ้นอยู่กับ
Class.of(context)การเปลี่ยนแปลง( รูปแบบ)
ซึ่งหมายความว่าbuildวิธีการที่ควรจะไม่ก่อให้เกิดการเรียกร้อง http หรือปรับเปลี่ยนใด ๆ ของรัฐ
เกี่ยวข้องกับคำถามนี้อย่างไร?
ปัญหาที่คุณกำลังเผชิญคือวิธีการสร้างของคุณมีผลข้างเคียง / ไม่บริสุทธิ์ทำให้การสร้างการโทรภายนอกเป็นเรื่องยุ่งยาก
แทนที่จะป้องกันการสร้างการโทรคุณควรทำให้วิธีการสร้างของคุณบริสุทธิ์เพื่อให้สามารถเรียกใช้ได้ตลอดเวลาโดยไม่มีผลกระทบ
ในกรณีของตัวอย่างของคุณที่คุณต้องการเปลี่ยนวิดเจ็ตของคุณให้เป็นStatefulWidgetแล้วดึงที่โทร HTTP ไปinitStateของคุณ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
},
);
}
}
ฉันรู้เรื่องนี้แล้ว ฉันมาที่นี่เพราะต้องการเพิ่มประสิทธิภาพการสร้างใหม่จริงๆ
นอกจากนี้ยังเป็นไปได้ที่จะสร้างวิดเจ็ตที่สามารถสร้างใหม่โดยไม่ต้องบังคับให้ลูก ๆ สร้างด้วย
เมื่ออินสแตนซ์ของวิดเจ็ตยังคงเหมือนเดิม การกระพือปีกอย่างตั้งใจจะไม่สร้างเด็กขึ้นมาใหม่ หมายความว่าคุณสามารถแคชบางส่วนของแผนผังวิดเจ็ตของคุณเพื่อป้องกันการสร้างใหม่โดยไม่จำเป็น
วิธีที่ง่ายที่สุดคือใช้ตัวconstสร้างโผ:
@override
Widget build(BuildContext context) {
return const DecoratedBox(
decoration: BoxDecoration(),
child: Text("Hello World"),
);
}
ด้วยconstคีย์เวิร์ดนั้นอินสแตนซ์ของDecoratedBoxจะยังคงเหมือนเดิมแม้ว่าบิลด์จะถูกเรียกหลายร้อยครั้งก็ตาม
แต่คุณสามารถบรรลุผลลัพธ์เดียวกันได้ด้วยตนเอง:
@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,
],
);
},
);
}
ในตัวอย่างนี้เมื่อ StreamBuilder ได้รับแจ้งค่าใหม่subtreeจะไม่สร้างใหม่แม้ว่า StreamBuilder / Column จะทำก็ตาม มันเกิดขึ้นเนื่องจากการปิดตัวอย่างMyWidgetไม่เปลี่ยนแปลง
รูปแบบนี้ถูกใช้มากในแอนิเมชั่น การใช้งานทั่วไปคือAnimatedBuilderและการเปลี่ยนทั้งหมดเช่นAlignTransition.
นอกจากนี้คุณยังสามารถจัดเก็บsubtreeลงในช่องของชั้นเรียนของคุณได้แม้ว่าจะแนะนำให้ใช้น้อยกว่าก็ตามเนื่องจากมันทำลายคุณสมบัติการโหลดซ้ำ