TL; ดร
อย่าใช้การคำนวณหนักภายในupdateShouldNotifyวิธีการและการใช้constแทน ใหม่เมื่อมีการสร้างเครื่องมือ
ก่อนอื่นเราควรทำความเข้าใจว่าอะไรคือ Widget, Element และ Render objects
- Render objects คือสิ่งที่แสดงบนหน้าจอจริงๆ พวกเขาไม่แน่นอนมีตรรกะการวาดภาพและเค้าโครง แผนผังการแสดงผลนั้นคล้ายกับ Document Object Model (DOM) ในเว็บมากและคุณสามารถดูวัตถุที่แสดงผลเป็นโหนด DOM ในโครงสร้างนี้
- วิดเจ็ต - คือรายละเอียดของสิ่งที่ควรแสดงผล พวกมันไม่เปลี่ยนรูปและราคาถูก ดังนั้นหากวิดเจ็ตตอบคำถาม "อะไร" (วิธีการสำแดง) วัตถุ Render จะตอบคำถามว่า "อย่างไร" (แนวทางที่จำเป็น) การเปรียบเทียบจากเว็บคือ "Virtual DOM"
- Element / BuildContext - เป็นพร็อกซีระหว่างวิดเจ็ตและอ็อบเจกต์Render มีข้อมูลเกี่ยวกับตำแหน่งของวิดเจ็ตในทรี * และวิธีการอัพเดตอ็อบเจ็กต์ Render เมื่อวิดเจ็ตที่เกี่ยวข้องมีการเปลี่ยนแปลง
ตอนนี้เราพร้อมที่จะดำน้ำในInheritedWidgetและ BuildContext ของวิธีinheritFromWidgetOfExactType
ตัวอย่างเช่นฉันแนะนำให้เราพิจารณาตัวอย่างนี้จากเอกสารของ Flutter เกี่ยวกับ InheritedWidget:
class FrogColor extends InheritedWidget {
const FrogColor({
Key key,
@required this.color,
@required Widget child,
}) : assert(color != null),
assert(child != null),
super(key: key, child: child);
final Color color;
static FrogColor of(BuildContext context) {
return context.inheritFromWidgetOfExactType(FrogColor);
}
@override
bool updateShouldNotify(FrogColor old) {
return color != old.color;
}
}
InheritedWidget - เพียงแค่เครื่องมือที่นำไปปฏิบัติในวิธีการที่สำคัญกรณีหนึ่งของเรา - updateShouldNotify
updateShouldNotify - ฟังก์ชันที่รับพารามิเตอร์oldWidgetหนึ่งพารามิเตอร์และส่งคืนค่าบูลีน: จริงหรือเท็จ
เช่นเดียวกับวิดเจ็ตใด ๆInheritedWidgetมีวัตถุองค์ประกอบที่เกี่ยวข้อง มันเป็นInheritedElement การเรียกใช้ InheritedElement updateShouldNotifyบนวิดเจ็ตทุกครั้งที่เราสร้างวิดเจ็ตใหม่ (เรียกใช้setStateบนบรรพบุรุษ) เมื่อupdateShouldNotifyส่งคืนจริง InheritedElement วนซ้ำผ่านการอ้างอิง (?) และเรียกเมธอดdidChangeDependenciesบนมัน
InheritedElement ได้รับการอ้างอิงที่ไหน? ที่นี่เราควรดูเมธอดinheritFromWidgetOfExactType
inheritFromWidgetOfExactType - เมธอดนี้กำหนดไว้ใน BuildContext และ
ทุกอิลิเมนต์จะใช้อินเทอร์เฟซ BuildContext (Element == BuildContext) ดังนั้นทุก Element จึงมีวิธีนี้
มาดูรหัสของ inheritFromWidgetOfExactType:
final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[targetType];
if (ancestor != null) {
assert(ancestor is InheritedElement);
return inheritFromElement(ancestor, aspect: aspect);
}
ที่นี่เราพยายามค้นหาบรรพบุรุษใน_inheritedWidgets ที่แมปตามประเภท ถ้าบรรพบุรุษที่พบเราแล้วโทรinheritFromElement
รหัสสำหรับinheritFromElement :
InheritedWidget inheritFromElement(InheritedElement ancestor, { Object aspect }) {
assert(ancestor != null);
_dependencies ??= HashSet<InheritedElement>();
_dependencies.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget;
}
- เราเพิ่มบรรพบุรุษเป็นการพึ่งพาขององค์ประกอบปัจจุบัน (_dependencies.add (บรรพบุรุษ))
- เราเพิ่มองค์ประกอบปัจจุบันในการอ้างอิงของบรรพบุรุษ (บรรพบุรุษ.updateDependencies (นี้, ด้าน))
- เราส่งคืนวิดเจ็ตของบรรพบุรุษอันเป็นผลมาจากinheritFromWidgetOfExactType (return บรรพบุรุษ. widget )
ตอนนี้เรารู้แล้วว่า InheritedElement ได้รับการอ้างอิงที่ไหน
ตอนนี้ให้ดูที่ วิธีdidChangeDependencies ทุกองค์ประกอบมีวิธีนี้:
void didChangeDependencies() {
assert(_active);
assert(_debugCheckOwnerBuildTargetExists('didChangeDependencies'));
markNeedsBuild();
}
ดังที่เราเห็นวิธีนี้เพียงแค่ทำเครื่องหมายองค์ประกอบว่าสกปรกและควรสร้างองค์ประกอบนี้ใหม่ในเฟรมถัดไปสร้างใหม่หมายถึงวิธีการโทรที่สร้างบนองค์ประกอบวิดเจ็ต coresponding
แต่สิ่งที่เกี่ยวกับ "ต้นไม้ย่อยทั้งต้นสร้างใหม่เมื่อฉันสร้าง InheritedWidget ใหม่" ที่นี่เราควรจำไว้ว่าวิดเจ็ตไม่เปลี่ยนรูปและหากคุณสร้างวิดเจ็ตใหม่ Flutter จะสร้างแผนผังย่อยขึ้นมาใหม่ เราจะแก้ไขได้อย่างไร?
- แคชวิดเจ็ตด้วยมือ (ด้วยตนเอง)
- ใช้constเนื่องจาก const สร้างค่า / คลาสเพียงอินสแตนซ์เดียว