TL; DR
Jangan gunakan komputasi berat di dalam metode updateShouldNotify dan gunakan const sebagai ganti yang baru saat membuat widget
Pertama-tama, kita harus memahami apa itu widget, Element, dan objek Render.
- Objek render adalah apa yang sebenarnya ditampilkan di layar. Mereka bisa berubah , mengandung logika lukisan dan tata letak. Pohon Render sangat mirip dengan Model Objek Dokumen (DOM) di web dan Anda dapat melihat objek render sebagai simpul DOM di pohon ini
- Widget - adalah deskripsi tentang apa yang harus dirender. Mereka tidak bisa diubah dan murah. Jadi jika Widget menjawab pertanyaan "Apa?" (Pendekatan deklaratif) maka objek Render menjawab pertanyaan "Bagaimana?" (Pendekatan imperatif). Sebuah analogi dari web adalah "DOM Virtual".
- Element / BuildContext - adalah proxy antara Widget dan objek Render . Ini berisi informasi tentang posisi widget di pohon * dan cara memperbarui objek Render ketika widget terkait diubah.
Sekarang kita siap untuk menyelami metode InheritedWidget dan BuildContext inheritFromWidgetOfExactType .
Sebagai contoh, saya sarankan kami mempertimbangkan contoh ini dari dokumentasi Flutter tentang 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 - hanya sebuah widget yang diimplementasikan dalam kasus kami satu metode penting - updateShouldNotify .
updateShouldNotify - fungsi yang menerima satu parameter oldWidget dan mengembalikan nilai boolean: true atau false.
Seperti widget lainnya, InheritedWidget memiliki objek Elemen yang sesuai. Itu adalah InheritedElement . Panggilan InheritedElement updateShouldNotify pada widget setiap kali kita membuat widget baru (panggil setState pada leluhur). Ketika updateShouldNotify mengembalikan True InheritedElement melakukan iterasi melalui dependensi (?) Dan memanggil metode didChangeDependencies padanya.
Di mana InheritedElement mendapatkan dependensi ? Di sini kita harus melihat metode inheritFromWidgetOfExactType .
inheritFromWidgetOfExactType - Metode ini ditentukan dalam BuildContext dan
setiap Elemen mengimplementasikan antarmuka BuildContext (Element == BuildContext). Jadi setiap Elemen memiliki metode ini.
Mari kita lihat kode inheritFromWidgetOfExactType:
final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[targetType];
if (ancestor != null) {
assert(ancestor is InheritedElement);
return inheritFromElement(ancestor, aspect: aspect);
}
Di sini kami mencoba menemukan leluhur di _inheritedWidgets yang dipetakan berdasarkan jenis. Jika leluhur ditemukan, kita kemudian memanggil inheritFromElement .
Kode untuk inheritFromElement :
InheritedWidget inheritFromElement(InheritedElement ancestor, { Object aspect }) {
assert(ancestor != null);
_dependencies ??= HashSet<InheritedElement>();
_dependencies.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget;
}
- Kami menambahkan leluhur sebagai ketergantungan elemen saat ini (_dependencies.add (leluhur))
- Kami menambahkan elemen saat ini ke dependensi leluhur (leluhur.updateDependencies (ini, aspek))
- Kami mengembalikan widget leluhur sebagai hasil dari inheritFromWidgetOfExactType (mengembalikan leluhur.widget )
Jadi sekarang kita tahu dari mana InheritedElement mendapatkan dependensinya.
Sekarang mari kita lihat metode didChangeDependencies . Setiap Elemen memiliki metode ini:
void didChangeDependencies() {
assert(_active); // otherwise markNeedsBuild is a no-op
assert(_debugCheckOwnerBuildTargetExists('didChangeDependencies'));
markNeedsBuild();
}
Seperti yang kita lihat, metode ini hanya menandai elemen sebagai kotor dan elemen ini harus dibangun kembali pada bingkai berikutnya. Rebuild berarti metode panggilan yang dibangun di atas elemen widget yang sesuai.
Tapi bagaimana dengan "Seluruh sub-pohon membangun kembali ketika saya membangun kembali InheritedWidget?". Di sini kita harus ingat bahwa Widget tidak dapat diubah dan jika Anda membuat widget baru Flutter akan membangun kembali sub-pohon. Bagaimana cara memperbaikinya?
- Widget cache dengan tangan (secara manual)
- Gunakan const karena const membuat satu-satunya instance dari nilai / kelas