Jawaban singkat:
React menjamin bahwa ref ditetapkan sebelum componentDidMount
atau componentDidUpdate
hook. Tetapi hanya untuk anak-anak yang benar-benar diberikan .
componentDidMount() {
}
componentDidUpdate() {
}
render() {
return <div ref={/* ... */} />;
}
Perhatikan ini tidak berarti “React selalu menetapkan semua ref sebelum hook ini berjalan”.
Mari kita lihat beberapa contoh di mana wasit tidak ditetapkan.
Referensi tidak ditetapkan untuk elemen yang tidak dirender
React hanya akan memanggil callback ref untuk elemen yang sebenarnya Anda kembalikan dari render .
Artinya jika kode Anda terlihat seperti
render() {
if (this.state.isLoading) {
return <h1>Loading</h1>;
}
return <div ref={this._setRef} />;
}
dan awalnya this.state.isLoading
adalah true
, Anda harus tidak mengharapkan this._setRef
untuk dipanggil sebelum componentDidMount
.
Ini seharusnya masuk akal: jika render pertama Anda dikembalikan <h1>Loading</h1>
, tidak ada cara yang mungkin bagi React untuk mengetahui bahwa dalam beberapa kondisi lain ia mengembalikan sesuatu yang lain yang membutuhkan ref untuk dilampirkan. Ada juga ada yang mengatur ref ke: pada <div>
elemen tidak diciptakan karena render()
metode mengatakan itu tidak boleh diberikan.
Jadi dengan contoh ini, hanya componentDidMount
akan menembak. Namun, saat this.state.loading
berubah menjadifalse
, Anda akan melihat this._setRef
lampiran terlebih dahulu, dan kemudian componentDidUpdate
akan aktif.
Hati-hati dengan komponen lainnya
Perhatikan bahwa jika Anda meneruskan turunan dengan ref ke komponen lain, ada kemungkinan mereka melakukan sesuatu yang mencegah rendering (dan menyebabkan masalah).
Misalnya, ini:
<MyPanel>
<div ref={this.setRef} />
</MyPanel>
tidak akan berfungsi jika MyPanel
tidak disertakan props.children
dalam outputnya:
function MyPanel(props) {
return <h1>Oops, no refs for you today!</h1>;
}
Sekali lagi, ini bukan bug: tidak akan ada apa-apa bagi React untuk menyetel ref karena elemen DOM tidak dibuat .
Referensi tidak disetel sebelum siklus proses jika mereka diteruskan ke bersarang ReactDOM.render()
Mirip dengan bagian sebelumnya, jika Anda meneruskan anak dengan ref ke komponen lain, mungkin saja komponen ini dapat melakukan sesuatu yang mencegah pelampiran ref pada waktunya.
Misalnya, mungkin itu tidak mengembalikan anak dari render()
, dan sebaliknya memanggil ReactDOM.render()
dalam pengait siklus hidup. Anda dapat menemukan contohnya di sini . Dalam contoh itu, kami merender:
<MyModal>
<div ref={this.setRef} />
</MyModal>
Tapi MyModal
melakukan ReactDOM.render()
panggilan nya componentDidUpdate
metode siklus hidup:
componentDidUpdate() {
ReactDOM.render(this.props.children, this.targetEl);
}
render() {
return null;
}
Sejak React 16, panggilan render tingkat atas tersebut selama siklus proses akan ditunda hingga siklus proses berjalan untuk keseluruhan pohon . Ini akan menjelaskan mengapa Anda tidak melihat wasit terlampir tepat waktu.
Solusi untuk masalah ini adalah menggunakan
portal, bukan ReactDOM.render
panggilan bersarang :
render() {
return ReactDOM.createPortal(this.props.children, this.targetEl);
}
Dengan cara ini kita <div>
dengan ref sebenarnya disertakan dalam keluaran render.
Jadi jika Anda mengalami masalah ini, Anda perlu memverifikasi tidak ada apa pun antara komponen Anda dan ref yang mungkin menunda rendering turunan.
Jangan gunakan setState
untuk menyimpan referensi
Pastikan Anda tidak menggunakan setState
untuk menyimpan ref di callback ref, karena asinkron dan sebelum "selesai", componentDidMount
akan dieksekusi terlebih dahulu.
Masih Masalah?
Jika tidak ada tip di atas yang membantu, ajukan masalah di React dan kami akan memeriksanya.
this
lingkup leksikal di luar kelas Anda. Cobalah untuk menyingkirkan sintaks fungsi panah untuk metode kelas Anda dan lihat apakah itu membantu.