คำตอบสั้น ๆ :
React รับประกันว่า refs ถูกตั้งค่าก่อนcomponentDidMountหรือcomponentDidUpdatehooks แต่สำหรับเด็กที่แสดงผลจริงเท่านั้น
componentDidMount() {
}
componentDidUpdate() {
}
render() {
return <div ref={/* ... */} />;
}
โปรดทราบว่านี่ไม่ได้หมายความว่า“ React จะตั้งค่าการอ้างอิงทั้งหมดก่อนที่ hooks เหล่านี้จะทำงานเสมอ”
ลองดูตัวอย่างบางส่วนที่ไม่ได้รับการอ้างอิง
Refs ไม่ได้รับการตั้งค่าสำหรับองค์ประกอบที่ไม่ได้แสดงผล
ตอบสนองจะโทรเรียกกลับโทษสำหรับองค์ประกอบจริงที่คุณกลับมาจากการแสดงผล
ซึ่งหมายความว่าหากรหัสของคุณมีลักษณะ
render() {
if (this.state.isLoading) {
return <h1>Loading</h1>;
}
return <div ref={this._setRef} />;
}
และต้นthis.state.isLoadingคือtrueคุณควรจะไม่ได้คาดหวังว่าจะได้รับการเรียกก่อนthis._setRefcomponentDidMount
สิ่งนี้น่าจะสมเหตุสมผล: หากการเรนเดอร์ครั้งแรกของคุณส่งคืน<h1>Loading</h1>ไม่มีทางเป็นไปได้ที่ React จะรู้ว่าภายใต้เงื่อนไขอื่น ๆ จะส่งคืนสิ่งอื่นที่จำเป็นต้องแนบการอ้างอิง นอกจากนี้ยังมีอะไรที่จะกำหนดโทษที่:<div>องค์ประกอบไม่ได้สร้างเพราะrender()วิธีการบอกว่ามันไม่ควรจะแสดงผล
ดังนั้นด้วยตัวอย่างนี้componentDidMountจะเริ่มทำงานเท่านั้น อย่างไรก็ตามเมื่อมีthis.state.loadingการเปลี่ยนแปลงfalseคุณจะเห็นไฟล์this._setRefแนบก่อนจากนั้นcomponentDidUpdateจะเริ่มทำงาน
ระวังส่วนประกอบอื่น ๆ
โปรดทราบว่าหากคุณส่งเด็กที่มีการอ้างอิงไปยังส่วนประกอบอื่น ๆมีโอกาสที่พวกเขาจะทำบางสิ่งที่ขัดขวางการแสดงผล (และทำให้เกิดปัญหา)
ตัวอย่างเช่นสิ่งนี้:
<MyPanel>
<div ref={this.setRef} />
</MyPanel>
จะไม่ทำงานหากMyPanelไม่ได้รวมprops.childrenไว้ในผลลัพธ์:
function MyPanel(props) {
return <h1>Oops, no refs for you today!</h1>;
}
อีกครั้งก็ไม่ได้เป็นปัญหา: จะมีอะไรให้ตอบสนองกับตั้งเตะโทษเพราะองค์ประกอบ DOM ก็ไม่ได้สร้าง
Refs ไม่ได้รับการตั้งค่าก่อนวงจรชีวิตหากส่งผ่านไปยังที่ซ้อน ReactDOM.render()
เช่นเดียวกับส่วนก่อนหน้านี้หากคุณส่งลูกที่มีการอ้างอิงไปยังส่วนประกอบอื่นเป็นไปได้ว่าส่วนประกอบนี้อาจทำบางอย่างที่ขัดขวางการแนบการอ้างอิงในเวลา
ตัวอย่างเช่นบางทีมันอาจจะไม่ส่งเด็กกลับมาrender()และกำลังโทรหาReactDOM.render()lifecycle hook แทน คุณสามารถค้นหาตัวอย่างนี้ที่นี่ ในตัวอย่างนั้นเราแสดง:
<MyModal>
<div ref={this.setRef} />
</MyModal>
แต่MyModalทำการReactDOM.render()โทรด้วย componentDidUpdateวิธีวงจรชีวิต:
componentDidUpdate() {
ReactDOM.render(this.props.children, this.targetEl);
}
render() {
return null;
}
ตั้งแต่ React 16 เช่นระดับบนสุดทำให้การโทรในช่วงวงจรชีวิตจะได้รับการเลื่อนออกไปจนกว่าวงจรชีวิตได้วิ่งไปที่ต้นไม้ทั้งหมด สิ่งนี้จะอธิบายว่าทำไมคุณไม่เห็นการอ้างอิงที่แนบมาในเวลา
วิธีแก้ปัญหานี้คือการใช้
พอร์ทัลแทนการReactDOM.renderเรียกซ้อน:
render() {
return ReactDOM.createPortal(this.props.children, this.targetEl);
}
วิธีนี้ของเราที่<div>มีการอ้างอิงจะรวมอยู่ในผลลัพธ์การแสดงผล
ดังนั้นหากคุณพบปัญหานี้คุณต้องตรวจสอบว่าไม่มีอะไรระหว่างองค์ประกอบของคุณและการอ้างอิงที่อาจทำให้การแสดงผลย่อยล่าช้า
อย่าใช้setStateเพื่อจัดเก็บการอ้างอิง
ตรวจสอบให้แน่ใจว่าคุณไม่ได้ใช้setStateเพื่อจัดเก็บการอ้างอิงในการเรียกกลับอ้างอิงเนื่องจากเป็นแบบอะซิงโครนัสและก่อนที่จะ "เสร็จสิ้น" componentDidMountจะดำเนินการก่อน
หากยังมีปัญหา
หากเคล็ดลับข้างต้นไม่มีความช่วยเหลือให้ยื่นปัญหาใน React แล้วเราจะตรวจสอบ
thisจากขอบเขตศัพท์นอกคลาสของคุณ ลองกำจัดไวยากรณ์ฟังก์ชันลูกศรสำหรับเมธอดคลาสของคุณและดูว่าช่วยได้หรือไม่