คำตอบสั้น ๆ :
React รับประกันว่า refs ถูกตั้งค่าก่อนcomponentDidMount
หรือcomponentDidUpdate
hooks แต่สำหรับเด็กที่แสดงผลจริงเท่านั้น
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._setRef
componentDidMount
สิ่งนี้น่าจะสมเหตุสมผล: หากการเรนเดอร์ครั้งแรกของคุณส่งคืน<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
จากขอบเขตศัพท์นอกคลาสของคุณ ลองกำจัดไวยากรณ์ฟังก์ชันลูกศรสำหรับเมธอดคลาสของคุณและดูว่าช่วยได้หรือไม่