TL; DR
Không sử dụng tính toán nặng bên trong phương thức updateShouldNotify và sử dụng const thay vì new khi tạo widget
Trước hết, chúng ta nên hiểu các đối tượng Widget, Element và Render là gì.
- Các đối tượng kết xuất là những gì thực sự được hiển thị trên màn hình. Chúng có thể thay đổi , chứa bức tranh và logic bố cục. Cây kết xuất rất giống với Mô hình đối tượng tài liệu (DOM) trên web và bạn có thể xem một đối tượng kết xuất như một nút DOM trong cây này
- Widget - là một mô tả về những gì sẽ được hiển thị. Chúng là bất biến và rẻ tiền. Vì vậy, nếu một Widget trả lời câu hỏi “Cái gì?” (Cách tiếp cận so sánh) thì một đối tượng Kết xuất trả lời câu hỏi “Làm thế nào?” (Cách tiếp cận mệnh lệnh). Một ví dụ từ web là "DOM ảo".
- Element / BuildContext - là một proxy giữa các đối tượng Widget và Render . Nó chứa thông tin về vị trí của một widget trong cây * và cách cập nhật đối tượng Render khi một widget tương ứng bị thay đổi.
Bây giờ chúng ta đã sẵn sàng đi sâu vào phương thức của InheritedWidget và BuildContext inheritFromWidgetOfExactType .
Để làm ví dụ, tôi khuyên chúng ta nên xem xét ví dụ này từ tài liệu của Flutter về 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 - chỉ là một widget triển khai một phương pháp quan trọng trong trường hợp của chúng ta - updateShouldNotify .
updateShouldNotify - một hàm chấp nhận một tham số oldWidget và trả về một giá trị boolean: true hoặc false.
Giống như bất kỳ widget nào, InheritedWidget có một đối tượng Element tương ứng. Đó là Thừa kế . InheritedElement gọi updateShouldNotify trên widget mỗi khi chúng ta tạo một widget mới (gọi setState trên tổ tiên). Khi updateShouldNotify trả về true, Inhe inheritElement sẽ lặp lại các gói phụ thuộc (?) Và gọi phương thức didChangeDependencies trên đó.
Nơi Inhe inheritElement nhận được các phụ thuộc ? Ở đây chúng ta nên xem xét phương thức inheritFromWidgetOfExactType .
inheritFromWidgetOfExactType - Phương thức này được định nghĩa trong BuildContext và
mọi Phần tử triển khai giao diện BuildContext (Phần tử == BuildContext). Vì vậy, mọi Element đều có phương thức này.
Hãy xem mã của inheritFromWidgetOfExactType:
final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[targetType];
if (ancestor != null) {
assert(ancestor is InheritedElement);
return inheritFromElement(ancestor, aspect: aspect);
}
Ở đây, chúng tôi cố gắng tìm tổ tiên trong _inheritedWidgets được ánh xạ theo loại. Nếu tổ tiên được tìm thấy, thì chúng ta gọi inheritFromElement .
Mã cho inheritFromElement :
InheritedWidget inheritFromElement(InheritedElement ancestor, { Object aspect }) {
assert(ancestor != null);
_dependencies ??= HashSet<InheritedElement>();
_dependencies.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget;
}
- Chúng tôi thêm tổ tiên dưới dạng phụ thuộc của phần tử hiện tại (_dependencies.add (tổ tiên))
- Chúng tôi thêm phần tử hiện tại vào các phụ thuộc của tổ tiên (parent.updateDependencies (this, khía cạnh))
- Chúng tôi trả về tiện ích của tổ tiên là kết quả của inheritFromWidgetOfExactType (trả lại tổ tiên.widget )
Vì vậy, bây giờ chúng ta biết Inhe inheritElement lấy các phụ thuộc của nó ở đâu.
Bây giờ chúng ta hãy xem xét phương thức didChangeDependencies . Mọi phần tử đều có phương thức này:
void didChangeDependencies() {
assert(_active); // otherwise markNeedsBuild is a no-op
assert(_debugCheckOwnerBuildTargetExists('didChangeDependencies'));
markNeedsBuild();
}
Như chúng ta có thể thấy, phương pháp này chỉ đánh dấu một phần tử là bẩn và phần tử này sẽ được xây dựng lại trên khung tiếp theo. Rebuild nghĩa là xây dựng phương thức gọi dựa trên phần tử widget tương ứng.
Nhưng còn "Toàn bộ cây con được xây dựng lại khi tôi xây dựng lại InheritedWidget thì sao?". Ở đây chúng ta nên nhớ rằng Widget là bất biến và nếu bạn tạo widget mới thì Flutter sẽ xây dựng lại cây con. Làm thế nào chúng ta có thể sửa chữa nó?
- Cache widget bằng tay (thủ công)
- Sử dụng const vì const tạo ra một trường hợp duy nhất của giá trị / lớp