Cara cepat memulai VUE3.0: Masuk dan pelajari
Dalam proyek React, ada banyak skenario dimana Ref
diperlukan. Misalnya, gunakan atribut ref
untuk mendapatkan node DOM dan mendapatkan instance objek ClassComponent; gunakan useRef
Hook React.createRef
membuat objek Ref untuk menyelesaikan masalah setInterval
yang tidak dapat memperoleh status terbaru; metode untuk membuat objek Ref
secara manual.
Meskipun Ref
sangat mudah digunakan, namun tetap saja menemui masalah dalam proyek sebenarnya. Artikel ini akan menyelesaikan berbagai masalah terkait Ref
dari perspektif kode sumber dan memperjelas apa yang dilakukan di balik API terkait ref
. Setelah membaca artikel ini, Anda mungkin memiliki pemahaman lebih dalam tentang Ref
.
Pertama-tama, ref
adalah singkatan dari reference
, yang merupakan referensi. Dalam file deklarasi tipe react
, Anda dapat menemukan beberapa tipe terkait Ref, dan tipe tersebut tercantum di sini.
RefObject<T> { arus baca saja: T |. interface MutableRefObject<T> { current: T; }
Saat menggunakan useRef
Hook , RefObject
/MutableRefObejct dikembalikan. Kedua tipe mendefinisikan struktur objek { current: T }
, TypeScript akan memperingatkan ⚠️ jika refObject.current
diubah.
const ref = useRef<string>(null) ref.current = '' // Kesalahan
TS: Tidak dapat ditetapkan ke "saat ini" karena ini adalah properti hanya-baca.
Lihat definisi metode useRef
. Fungsi kelebihan beban digunakan di sini. Jika parameter generik MutableRefObject<T>
masuk T
tidak berisi null
, null
RefObject<T>
dikembalikan.
fungsi useRef<T>(initialValue: T): MutableRefObject<T>; function useRef<T>(initialValue: T | null): RefObject<T>;
Jadi, jika Anda ingin properti objek ref yang dibuat saat ini dapat dimodifikasi, Anda perlu menambahkan | null
.
const ref = gunakanRef<string |.null>(null) ref.current = '' // Oke,
saat memanggil metode React.createRef()
, RefObject
juga dikembalikan.
createRef
createRef(): RefObject { const refObject = { saat ini: nol, }; jika (__DEV__) { Objek.seal(refObject); } kembalikan refObject; }
RefObject/MutableRefObject
ditambahkan di versi 16.3
. Jika Anda menggunakan versi sebelumnya, Anda perlu menggunakan Ref Callback
.
Menggunakan Ref Callback
adalah meneruskan fungsi panggilan balik. Saat reaksi memanggil kembali, instance terkait akan diteruskan kembali, dan dapat disimpan dengan sendirinya untuk dipanggil. Jenis fungsi panggilan balik ini adalah RefCallback
.
ketik RefCallback<T> = (contoh: T | null) =>
RefCallback
; kelas ekspor CustomTextInput memperluas React.Component { masukan teks: HTMLInputElement |.null = null; saveInputRef = (elemen: HTMLInputElement | null) => { this.textInput = elemen; } memberikan() { kembali ( <input type="text" ref={ini.saveInputRef} /> ); } }
Dalam deklarasi tipe, terdapat juga tipe Ref/LegacyRef, yang digunakan untuk merujuk pada tipe Ref secara umum. LegacyRef
adalah versi yang kompatibel. Pada versi lama sebelumnya, ref
juga bisa berupa string.
ketik Ref<T> = RefCallback<T> |.RefObject<T> |. type LegacyRef<T> = string |.Ref<T>;
Hanya dengan memahami tipe-tipe yang terkait dengan Ref Anda dapat menjadi lebih nyaman menulis TypeScript.
MelewatiSaat menggunakan ref
pada komponen JSX, kita menyetel Ref
ke atribut ref
. Kita semua tahu bahwa sintaks jsx
akan dikompilasi ke dalam bentuk createElement
dengan alat seperti Babel.
//jsx <Ref Aplikasi={ref} id="aplikasi-saya" ></Aplikasi> // dikompilasi ke React.createElement(Aplikasi, { referensi: referensi, id: "aplikasi saya" });
Tampaknya ref
tidak berbeda dengan props lainnya, tetapi jika Anda mencoba mencetak props.ref di dalam komponen, hasilnya adalah undefined
. Dan konsol lingkungan dev
akan memberikan petunjuk.
Mencoba mengaksesnya akan menghasilkan
undefined
yang dikembalikan. Jika Anda perlu mengakses nilai yang sama dalam komponen anak, Anda harus meneruskannya sebagai prop yang berbeda.
Apa yang dilakukan React dengan ref? Seperti yang Anda lihat di kode sumber ReactElement, ref
adalah RESERVED_PROPS
. key
juga memiliki perlakuan ini. Kunci tersebut akan diproses dan diekstraksi secara khusus dari props dan diteruskan ke Element
.
const RESERVED_PROPS = { kunci: benar, referensi: benar, __diri: benar, __sumber: benar, };
Jadi ref
adalah “props“
yang akan diperlakukan secara khusus.
Sebelum versi 16.8.0
, Komponen Fungsi tidak memiliki kewarganegaraan dan hanya akan dirender berdasarkan props yang masuk. Dengan Hook, Anda tidak hanya dapat memiliki status internal, tetapi juga mengekspos metode untuk panggilan eksternal (memerlukan forwardRef
dan useImperativeHandle
).
Jika Anda menggunakan ref
secara langsung untuk Function Component
, konsol di lingkungan dev akan memperingatkan Anda bahwa Anda perlu membungkusnya dengan forwardRef
.
fungsiMasukan() { kembali <masukan /> } const ref = gunakanRef() <Input ref={ref} />
Komponen fungsi tidak dapat diberikan referensi. Upaya untuk mengakses referensi ini akan gagal. Apakah Anda bermaksud menggunakan React.forwardRef()
forwardRef
Lihat kode sumber ReactForwardRef.js. Lipat kode terkait __DEV__
Ini hanyalah komponen tingkat tinggi yang sangat sederhana. Terima FunctionComponent yang dirender, bungkus dan definisikan $$typeof
sebagai REACT_FORWARD_REF_TYPE
, lalu return
.
Lacak kodenya dan temukan resolusiLazyComponentTag, tempat $$typeof
akan diurai ke dalam WorkTag yang sesuai.
WorkTag yang sesuai dengan REACT_FORWARD_REF_TYPE
adalah ForwardRef. Kemudian ForwardRef akan masuk ke logika updateForwardRef.
kasus MajuRef: { anak = updateForwardRef( batal, pekerjaan Sedang Berlangsung, Komponen, alat peraga terselesaikan, renderLanes, ); kembalinya anak; }
Metode ini akan memanggil metode renderWithHooks dan meneruskan ref
pada parameter kelima.
berikutnyaAnak-anak = renderWithHooks( saat ini, pekerjaan Sedang Berlangsung, memberikan, alat peraga berikutnya, ref, // di sini renderLanes, );
Lanjutkan menelusuri kode dan masukkan metode renderWithHooks. Anda dapat melihat bahwa ref
akan diteruskan sebagai parameter kedua dari Component
. Pada titik ini kita dapat memahami dari mana ref
parameter kedua dari FuncitonComponent
yang dibungkus oleh forwardRef
(dibandingkan dengan parameter kedua konstruktor ClassComponent yaitu Konteks).
Mengetahui cara mengoper wasit, pertanyaan selanjutnya adalah bagaimana cara pemberian wasit.
(tetapkan RefCallback ke ref dan break point di callback). Lacak kode commitAttachRef. Dalam metode ini, akan dinilai apakah ref dari node Fiber adalah function
atau RefObject, dan instance akan diproses sesuai jenisnya. Jika node Fiber adalah HostComponent ( tag = 5
), yang merupakan node DOM, instance adalah node DOM; dan jika node Fiber adalah ClassComponent ( tag = 1
), instance adalah instance objek.
fungsi commitAttachRef(selesaiPekerjaan) { var ref = pekerjaan selesai.ref; jika (ref !== nol) { var instanceToUse = finishWork.stateNode; if (typeof ref === 'fungsi') { ref(instanceToUse); } kalau tidak { ref.saat ini = instanceToUse; } } }
Di atas adalah logika penugasan ref di HostComponent dan ClassComponent. Untuk komponen tipe ForwardRef, kode yang digunakan berbeda, tetapi perilakunya pada dasarnya sama. Anda dapat melihat imperatifHandleEffect di sini.
Selanjutnya, kita terus menggali kode sumber React untuk melihat bagaimana useRef diimplementasikan.
menemukan kode runtime useRef ReactFiberHooks dengan melacak kode tersebut
Ada dua metode di sini, mountRef
dan updateRef
. Seperti namanya, keduanya sesuai dengan operasi pada ref
saat node Fiber
mount
dan update
.
fungsi updateRef<T>(Nilai Awal: T): {|saat ini: T|} { const hook = updateWorkInProgressHook(); kembalikan hook.memoizedState; } function mountRef<T>(initialValue: T): {|saat ini: T|} { const hook = mountWorkInProgressHook(); const ref = {saat ini: nilai awal}; hook.memoizedState = ref; kembalikan referensi; }
Anda dapat melihat bahwa ketika mount
, useRef
membuat RefObject
dan menugaskannya ke memoizedState
hook
Saat update
, ia dikeluarkan dan dikembalikan secara langsung.
Hook yang berbeda memoizedState menyimpan konten yang berbeda. useState
menyimpan informasi state
, useEffect
menyimpan objek effect
, useRef
menyimpan objek ref
...
Metode mountWorkInProgressHook
dan updateWorkInProgressHook
didukung oleh daftar Hooks yang tertaut mengambil objek memoizedState yang sama setiap kali Anda merender useRef Sesederhana itu.
Pada titik ini, kita memahami logika meneruskan dan menetapkan ref
di React, serta kode sumber yang terkait dengan useRef
. Gunakan pertanyaan aplikasi untuk menggabungkan poin pengetahuan di atas: Ada komponen Input. Di dalam komponen, innerRef HTMLInputElement
perlu digunakan untuk mengakses node DOM
untuk menerapkannya?
const Masukan = forwardRef((alat peraga, ref) => { const innerRef = useRef<HTMLInputElement>(null) kembali ( <masukan {...alat peraga} ref={???} /> ) })
Perhatikan bagaimana penulisan ???
pada kode di atas.
============ Garis pemisah jawaban ==============
Dengan memahami implementasi internal terkait Ref, jelas kita dapat membuat RefCallback
di sini, yang dapat menangani banyak. Cukup tetapkan ref
.
fungsi ekspor menggabungkanRefs<T = any>( referensi: Array<MutableRefObject<T |.null> |.RefCallback<T>> ): React.RefCallback<T> { nilai kembalian => { refs.forEach(ref => { if (typeof ref === 'fungsi') { ref(nilai); } lain jika (ref !== null) { ref.saat ini = nilai; } }); }; } const Masukan = forwardRef((alat peraga, ref) => { const innerRef = useRef<HTMLInputElement>(null) kembali ( <input {...props} ref={combineRefs(ref, innerRef)} /> ) })