Masalah
Saya mengatur react ref
menggunakan definisi fungsi inline
render = () => {
return (
<div className="drawer" ref={drawer => this.drawerRef = drawer}>
maka componentDidMount
referensi DOM tidak disetel
componentDidMount = () => {
// this.drawerRef is not defined
Pemahaman saya adalah ref
callback harus dijalankan selama mount, namun console.log
pernyataan menambahkan mengungkapkan componentDidMount
dipanggil sebelum fungsi callback ref.
Contoh kode lain yang saya lihat misalnya diskusi di github ini menunjukkan asumsi yang sama, componentDidMount
harus dipanggil setelahref
panggilan balik apa pun yang ditentukan render
, bahkan dinyatakan dalam percakapan
Jadi componentDidMount dijalankan setelah semua callback ref dijalankan?
Iya.
Saya menggunakan react 15.4.1
Sesuatu yang lain saya sudah mencoba
Untuk memverifikasi ref
fungsi itu dipanggil, saya mencoba mendefinisikannya di kelas seperti itu
setDrawerRef = (drawer) => {
this.drawerRef = drawer;
}
lalu masuk render
<div className="drawer" ref={this.setDrawerRef}>
Konsol logging dalam hal ini mengungkapkan bahwa callback memang dipanggil setelahnya componentDidMount
sumber
this
lingkup leksikal di luar kelas Anda. Cobalah untuk menyingkirkan sintaks fungsi panah untuk metode kelas Anda dan lihat apakah itu membantu.render
dan karenanya perlu memanfaatkancomponentDidUpdate
, karenacomponentDidMount
bukan bagian dari siklus proses pembaruan . Mungkin bukan masalah Anda, tetapi menurut Anda ini layak untuk diangkat sebagai solusi potensial.ref callbacks are invoked before componentDidMount or componentDidUpdate lifecycle hooks.
tetapi ini tampaknya tidak benar :(ref = {ref => { this.drawerRef = ref }}
2. bahkan ref dipanggil sebelum componentDidMount; ref hanya dapat diakses setelah render awal ketika div dalam kasus Anda dirender. Jadi, Anda harus bisa mengakses ref di tingkat berikutnya, misalnya di componentWillReceiveProps menggunakanthis.drawerRef
3. Jika Anda mencoba mengakses sebelum pemasangan awal, Anda hanya akan mendapatkan nilai ref yang tidak ditentukan.Jawaban:
Jawaban singkat:
React menjamin bahwa ref ditetapkan sebelum
componentDidMount
ataucomponentDidUpdate
hook. Tetapi hanya untuk anak-anak yang benar-benar diberikan .componentDidMount() { // can use any refs here } componentDidUpdate() { // can use any refs here } render() { // as long as those refs were rendered! 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
adalahtrue
, Anda harus tidak mengharapkanthis._setRef
untuk dipanggil sebelumcomponentDidMount
.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 karenarender()
metode mengatakan itu tidak boleh diberikan.Jadi dengan contoh ini, hanya
componentDidMount
akan menembak. Namun, saatthis.state.loading
berubah menjadifalse
, Anda akan melihatthis._setRef
lampiran terlebih dahulu, dan kemudiancomponentDidUpdate
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 disertakanprops.children
dalam outputnya:function MyPanel(props) { // ignore props.children 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 memanggilReactDOM.render()
dalam pengait siklus hidup. Anda dapat menemukan contohnya di sini . Dalam contoh itu, kami merender:<MyModal> <div ref={this.setRef} /> </MyModal>
Tapi
MyModal
melakukanReactDOM.render()
panggilan nyacomponentDidUpdate
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 referensiPastikan 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.
sumber
Pengamatan yang berbeda dari masalah tersebut.
Saya menyadari bahwa masalah hanya terjadi saat dalam mode pengembangan. Setelah penyelidikan lebih lanjut, saya menemukan bahwa menonaktifkan
react-hot-loader
konfigurasi Webpack saya mencegah masalah ini.saya menggunakan
Dan itu adalah aplikasi elektron.
Konfigurasi pengembangan Webpack parsial saya
const webpack = require('webpack') const merge = require('webpack-merge') const baseConfig = require('./webpack.config.base') module.exports = merge(baseConfig, { entry: [ // REMOVED THIS -> 'react-hot-loader/patch', `webpack-hot-middleware/client?path=http://localhost:${port}/__webpack_hmr`, '@babel/polyfill', './app/index' ], ... })
Menjadi mencurigakan ketika saya melihat bahwa menggunakan fungsi sebaris di render () berhasil, tetapi menggunakan metode terikat macet.
Bekerja dalam hal apa pun
class MyComponent { render () { return ( <input ref={(el) => {this.inputField = el}}/> ) } }
Crash dengan react-hot-loader (ref tidak ditentukan di componentDidMount)
class MyComponent { constructor (props) { super(props) this.inputRef = this.inputRef.bind(this) } inputRef (input) { this.inputField = input } render () { return ( <input ref={this.inputRef}/> ) } }
Sejujurnya, hot reload sering kali bermasalah untuk mendapatkan yang "benar". Dengan alat pengembang yang diperbarui dengan cepat, setiap proyek memiliki konfigurasi yang berbeda. Mungkin konfigurasi khusus saya bisa diperbaiki. Saya akan memberi tahu Anda di sini jika itu masalahnya.
sumber
Masalah ini juga dapat muncul saat Anda mencoba menggunakan ref dari komponen yang dilepas seperti menggunakan ref dalam setinterval dan tidak menghapus interval set selama pelepasan komponen.
componentDidMount(){ interval_holder = setInterval(() => { this.myref = "something";//accessing ref of a component }, 2000); }
selalu hapus interval seperti misalnya,
componentWillUnmount(){ clearInterval(interval_holder) }
sumber