Cô bạn đi hai giải pháp!
1. Sửa đổi ChangeDetectionStrargety thành OnPush
Đối với giải pháp này, về cơ bản, bạn nói với góc cạnh:
Dừng kiểm tra các thay đổi; tôi sẽ làm điều đó chỉ khi tôi biết là cần thiết
Cách khắc phục nhanh:
Sửa đổi thành phần của bạn để nó sẽ sử dụng ChangeDetectionStrategy.OnPush
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnInit {
// ...
}
Với điều này, mọi thứ dường như không còn hoạt động nữa. Đó là bởi vì từ giờ trở đi bạn sẽ phải gọi AngulardetectChanges()
theo cách thủ công.
this.cdr.detectChanges();
Đây là một liên kết giúp tôi hiểu đúng ChangeDetectionStrargety :
https://alligator.io/angular/change-detection-strargety/
2. Hiểu về ExpressionChangedAfterItHasBeenCheckedError
Đây là một trích xuất nhỏ từ tomonari_t câu trả lời của về nguyên nhân gây ra lỗi này, tôi đã cố gắng chỉ bao gồm các phần giúp tôi hiểu điều này.
Toàn bộ bài viết cho thấy các ví dụ mã thực về mọi điểm được hiển thị ở đây.
Nguyên nhân sâu xa là vòng đời góc cạnh:
Sau mỗi thao tác Angular ghi nhớ những giá trị mà nó đã sử dụng để thực hiện một thao tác. Chúng được lưu trữ trong thuộc tính oldValues của chế độ xem thành phần.
Sau khi kiểm tra xong tất cả các thành phần, Angular sẽ bắt đầu chu trình phân loại tiếp theo nhưng thay vì thực hiện các thao tác, nó so sánh các giá trị hiện tại với các giá trị mà nó nhớ từ chu trình phân loại trước đó.
Các hoạt động sau đây đang được kiểm tra tại chu trình tiêu hóa:
kiểm tra xem các giá trị được truyền xuống các thành phần con có giống với các giá trị sẽ được sử dụng để cập nhật các thuộc tính của các thành phần này không.
kiểm tra xem các giá trị được sử dụng để cập nhật các phần tử DOM có giống với các giá trị sẽ được sử dụng để cập nhật các phần tử này hiện thực hiện như nhau không.
kiểm tra tất cả các thành phần con
Và do đó, lỗi được đưa ra khi các giá trị so sánh là khác nhau. , blogger Max Koretskyi tuyên bố:
Thủ phạm luôn là thành phần con hoặc chỉ thị.
Và cuối cùng đây là một số mẫu trong thế giới thực thường gây ra lỗi này:
- Chia sẻ dịch vụ
- Phát sóng sự kiện đồng bộ
- Khởi tạo thành phần động
Mỗi mẫu có thể được tìm thấy ở đây (plunkr), trong trường hợp của tôi, vấn đề là một khởi tạo thành phần động.
Ngoài ra, bằng kinh nghiệm của riêng tôi, tôi khuyên mọi người nên tránh setTimeout
giải pháp, trong trường hợp của tôi đã gây ra một vòng lặp vô hạn "gần như" (21 cuộc gọi mà tôi không sẵn sàng chỉ cho bạn cách khiêu khích họ),
Tôi khuyên bạn nên luôn luôn ghi nhớ vòng đời của Angular để bạn có thể tính đến việc chúng sẽ bị ảnh hưởng như thế nào mỗi khi bạn sửa đổi giá trị của thành phần khác. Với lỗi này, Angular đang nói với bạn:
Bạn có thể làm điều này sai cách, bạn có chắc là bạn đúng không?
Blog tương tự cũng nói:
Thông thường, cách khắc phục là sử dụng móc phát hiện thay đổi bên phải để tạo thành phần động
Một hướng dẫn ngắn cho tôi là xem xét ít nhất hai điều sau đây trong khi mã hóa ( tôi sẽ cố gắng bổ sung theo thời gian ):
- Thay vào đó, hãy sửa đổi các giá trị thành phần cha mẹ từ các thành phần con của nó: thay đổi chúng từ cha mẹ của nó.
- Khi bạn sử dụng
@Input
và @Output
chỉ thị cố gắng tránh kích hoạt thay đổi lyfecycl trừ khi thành phần được khởi tạo hoàn toàn.
- Tránh các cuộc gọi không cần thiết của
this.cdr.detectChanges();
chúng có thể gây ra nhiều lỗi hơn, đặc biệt khi bạn xử lý nhiều dữ liệu động
- Khi việc sử dụng
this.cdr.detectChanges();
là bắt buộc, hãy đảm bảo rằng các biến ( @Input, @Output, etc
) đang được sử dụng được điền / khởi tạo ở móc phát hiện bên phải ( OnInit, OnChanges, AfterView, etc
)
- Khi có thể, loại bỏ thay vì ẩn , điều này có liên quan đến điểm 3 và 4.
Cũng thế
Nếu bạn muốn hiểu đầy đủ Angular Life Hook, tôi khuyên bạn nên đọc tài liệu chính thức tại đây: