Với OnPush, Angular chỉ kiểm tra component khi có một trong các tín hiệu: input thay đổi tham chiếu, event từ template của chính nó, async pipe phát giá trị, hoặc signal đọc trong template thay đổi. Ngoài các trường hợp đó, dù dữ liệu đã đổi, view vẫn giữ nguyên.
Ba nguyên nhân hay gặp:
// 1. mutate object input thay vì thay mới
this.user.name = 'new' // cùng tham chiếu → không check lại
this.user = { ...this.user, name: 'new' } // đúng
// 2. state đổi từ bên ngoài template của component
this.socket.onMessage(msg => {
this.messages.push(msg)
this.cdr.markForCheck() // đánh dấu component này + các cha là dirty
})
// 3. tự subscribe rồi gán, thay vì dùng async pipePhân biệt hai API dễ nhầm:
- markForCheck(): đánh dấu component và toàn bộ component cha phía trên là dirty để vòng change detection kế tiếp kiểm tra. Đây là lựa chọn đúng cho OnPush.
- detectChanges(): chạy change detection ngay lập tức cho component và cây con. Nặng hơn và dễ gây lỗi NG0100 nếu gọi sai lúc.
Hướng bền vững hơn là chuyển state sang signal hoặc dùng async pipe — cả hai tự đánh dấu dirty, không phải nhớ gọi markForCheck thủ công.