เธอไปสองทางแก้ปัญหา!
1. แก้ไขChangeDetectionStrategyเป็น OnPush
สำหรับวิธีนี้คุณจะบอกมุม:
หยุดตรวจสอบการเปลี่ยนแปลง ฉันจะทำก็ต่อเมื่อรู้ว่าจำเป็นเท่านั้น
การแก้ไขอย่างรวดเร็ว:
ปรับเปลี่ยนองค์ประกอบของคุณเพื่อที่จะใช้ ChangeDetectionStrategy.OnPush
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnInit {
// ...
}
ด้วยสิ่งนี้ดูเหมือนจะไม่ทำงานอีกต่อไป นั่นเป็นเพราะต่อจากนี้ไปคุณจะต้องทำการโทรdetectChanges()
ด้วยตนเองด้วยตนเอง
this.cdr.detectChanges();
นี่คือลิงค์ที่ช่วยให้ฉันเข้าใจChangeDetectionStrategyถูกต้อง:
https://alligator.io/angular/change-detection-strategy/
2. การทำความเข้าใจ ExpressionChangedAfterItHasBeenCheckedError
นี่คือสารสกัดขนาดเล็กจากtomonari_t ตอบเกี่ยวกับสาเหตุของข้อผิดพลาดนี้ฉันพยายามรวมเฉพาะส่วนที่ช่วยให้ฉันเข้าใจสิ่งนี้
บทความฉบับเต็มแสดงตัวอย่างรหัสจริงเกี่ยวกับทุกจุดที่แสดงที่นี่
สาเหตุที่แท้จริงคือวงจรชีวิตเชิงมุม:
หลังจากการดำเนินการแต่ละครั้ง Angular จดจำค่าที่ใช้ในการดำเนินการ พวกเขาจะถูกเก็บไว้ในคุณสมบัติ oldValues ของมุมมององค์ประกอบ
หลังจากการตรวจสอบเสร็จสิ้นสำหรับส่วนประกอบทั้งหมดแล้ว Angular จะเริ่มรอบการแยกย่อยถัดไป แต่แทนที่จะทำการดำเนินการจะเปรียบเทียบค่าปัจจุบันกับค่าที่จดจำจากรอบการแยกย่อยก่อนหน้า
การดำเนินการต่อไปนี้เป็นการตรวจสอบที่รอบย่อยของ:
ตรวจสอบว่าค่าที่ส่งผ่านลงไปยังคอมโพเนนต์ชายน์เหมือนกับค่าที่จะใช้เพื่ออัพเดตคุณสมบัติของคอมโพเนนต์เหล่านี้ทันที
ตรวจสอบว่าค่าที่ใช้เพื่ออัปเดตองค์ประกอบ DOM เหมือนกันกับค่าที่จะใช้ในการอัปเดตองค์ประกอบเหล่านี้ในขณะนี้ทำงานเหมือนกัน
ตรวจสอบองค์ประกอบย่อยทั้งหมด
ดังนั้นข้อผิดพลาดจะถูกโยนเมื่อค่าเปรียบเทียบแตกต่างกัน , Blogger Max Koretskyiกล่าวว่า:
ผู้ร้ายมักเป็นส่วนประกอบของลูกหรือคำสั่งเสมอ
และสุดท้ายนี่คือตัวอย่างโลกแห่งความจริงที่มักจะทำให้เกิดข้อผิดพลาดนี้:
- บริการที่ใช้ร่วมกัน
- การถ่ายทอดเหตุการณ์แบบซิงโครนัส
- การสร้างองค์ประกอบแบบไดนามิก
ทุกตัวอย่างสามารถพบได้ที่นี่ (plunkr) ในกรณีของฉันปัญหาคือการสร้างอินสแตนซ์คอมโพเนนต์
นอกจากนี้จากประสบการณ์ของฉันฉันขอแนะนำให้ทุกคนหลีกเลี่ยง setTimeout
แก้ปัญหาในกรณีของฉันทำให้เกิดการวนซ้ำ "เกือบ" (21 สายที่ฉันไม่ต้องการแสดงวิธียั่วพวกเขา)
ฉันขอแนะนำให้คำนึงถึงวงจรชีวิตเชิงมุมของแองกูลาร์เสมอเพื่อให้คุณสามารถพิจารณาว่าจะได้รับผลกระทบได้อย่างไรทุกครั้งที่คุณแก้ไขค่าขององค์ประกอบอื่น ด้วยข้อผิดพลาดนี้ Angular กำลังบอกคุณ:
คุณอาจทำสิ่งนี้ผิดวิธีคุณแน่ใจหรือไม่?
บล็อกเดียวกันก็บอกว่า:
บ่อยครั้งที่การแก้ไขคือการใช้เบ็ดตรวจจับการเปลี่ยนแปลงที่ถูกต้องเพื่อสร้างองค์ประกอบแบบไดนามิก
คำแนะนำสั้น ๆ สำหรับฉันคือการพิจารณาอย่างน้อยสองสิ่งต่อไปนี้ในขณะที่การเขียนโค้ด ( ฉันจะพยายามเติมเต็มเมื่อเวลาผ่านไป ):
- หลีกเลี่ยงการแก้ไขค่าองค์ประกอบหลักจากเป็นองค์ประกอบของเด็กแทน: แก้ไขจากองค์ประกอบหลัก
- เมื่อคุณใช้
@Input
และ@Output
คำสั่งพยายามหลีกเลี่ยงการทริกเกอร์การเปลี่ยนแปลง lyfecycle เว้นแต่ว่าองค์ประกอบจะเริ่มต้นได้อย่างสมบูรณ์
- หลีกเลี่ยงการโทรที่ไม่จำเป็น
this.cdr.detectChanges();
เพราะอาจทำให้เกิดข้อผิดพลาดมากขึ้นโดยเฉพาะอย่างยิ่งเมื่อคุณต้องจัดการกับข้อมูลแบบไดนามิกจำนวนมาก
- เมื่อการใช้งาน
this.cdr.detectChanges();
เป็นสิ่งจำเป็นตรวจสอบให้แน่ใจว่าตัวแปร ( @Input, @Output, etc
) ที่ใช้ถูกเติม / กำหนดค่าเริ่มต้นที่ hook การตรวจสอบที่ถูกต้อง ( OnInit, OnChanges, AfterView, etc
)
- เมื่อเป็นไปได้ให้ลบออกมากกว่าซ่อนนี่จะเกี่ยวข้องกับจุด 3 และ 4
ด้วย
หากคุณต้องการเข้าใจ Angular Life Hook ฉันขอแนะนำให้คุณอ่านเอกสารอย่างเป็นทางการที่นี่: