Kebanyakan orang yang bekerja di frontend, dengan satu atau lain cara, mendapat reaksi. Ini adalah perpustakaan JavaScript yang membantu menciptakan antarmuka yang keren, dalam beberapa tahun terakhir ini telah mendapatkan popularitas yang luar biasa. Namun, tidak banyak orang yang tahu cara kerjanya di dalam.
Dalam seri artikel ini, kami membaca kode dan mencoba mencari tahu apa yang bertanggung jawab atas paket yang berada di balik tudung untuk reaksi, untuk apa mereka digunakan dan bagaimana cara kerjanya. Yang paling dasar yang kami gunakan di browser adalah react
, react-dom
, events
, dan react-reconciler
.
Kami akan bergerak secara berurutan dan hari ini kami memiliki artikel tentang paket react
. Siapa yang peduli apa yang ada dalam paket ini - pergi di bawah kucing.
Pertama-tama, kami akan membuat contoh kecil, atas dasar mana kami akan mempertimbangkan paket ini. Gadget kami akan terlihat seperti ini:
function App() { const [text, changeText] = React.useState('Initial'); return ( <div className="app"> <span>{text}</span> <input type="text" value={text} onInput={(e) => changeText(e.target.value)} /> </div> ); } ReactDOM.render( <App />, document.getElementById('root') ) ;
Mari kita lihat sekilas kode ini. Di sini kita melihat panggilan hook melalui React.useState('Initial')
, sedikit JSX dan panggilan metode render untuk mendapatkan semua ini di halaman.
Bahkan, seperti yang diketahui banyak orang, ini bukan kode final yang diproses browser. Sebelum dieksekusi, ia dipindahkan, misalnya, dengan babel. Dalam hal ini, fungsi yang dikembalikan akan berubah menjadi sebagai berikut:
return React.createElement( "div", { className: "app" }, React.createElement("span", null, text), React.createElement("input", { type: "text", value: text, onInput: function onInput(e) { return changeText(e.target.value); } }) );
Siapa yang peduli untuk bereksperimen dan melihat bagaimana kode babel Anda berubah menjadi - babel repl .
React.createElement
Jadi, kami mendapat banyak panggilan ke React.createElement()
dan waktu untuk melihat apa fungsi ini. Kami akan menjelaskannya dalam kata-kata (atau Anda juga dapat melihat file - ReactElement.js ).
Pertama-tama, ia memeriksa apakah kita memiliki alat peraga (dalam kode, objek dengan alat peraga yang kita lewati disebut config
).
Selanjutnya, kami memeriksa untuk melihat apakah kami memiliki key
dan alat peraga ref
yang tidak undefined
, dan menyimpannya, jika ada.
if (hasValidKey(config)) { key = '' + config.key; }
Suatu hal yang menarik adalah config.key
ke string, yang berarti Anda dapat meneruskan tipe data apa pun sebagai kunci, hal utama adalah menerapkan metode .toString()
atau .valueOf()
dan mengembalikan nilai unik ke set tertentu.
Berikutnya adalah langkah-langkah berikut:
- salin alat peraga yang diteruskan ke elemen;
- tambahkan bidang
children
- children
sana jika kita melewati mereka bukan dengan alat peraga, tetapi sebagai elemen bersarang; - kami menetapkan nilai default dari
defaultProps
untuk properti-properti yang tidak kami tentukan sebelumnya.
Ketika kami telah menyiapkan semua data, kami memanggil fungsi internal yang membuat objek yang menggambarkan komponen kami. Objek ini terlihat seperti ini:
{ // This tag allows us to uniquely identify this as a React Element $$typeof: REACT_ELEMENT_TYPE, // Symbol // Built-in properties that belong on the element type: type, key: key, ref: ref, props: props, // Record the component responsible for creating this element. _owner: owner, }
Di sini kita memiliki properti $$typeof
, yang merupakan simbol, jadi lupakan objek mana yang akan gagal.
type
properti menyimpan tipe elemen yang akan dibuat. Dalam contoh kita, ini akan menjadi fungsi App()
dan baris 'div'
, 'span'
dan 'input'
.
Properti key
akan berisi kunci yang sama, karena itu lalat terbang ke konsol.
Alat peraga akan berisi apa yang kami lewati, children
- children
dan apa yang ditentukan dalam defaultProps
. Properti _owner
diperlukan untuk pekerjaan yang benar dengan ref
.
Diterjemahkan ke contoh kami, hasil React.createElement(App, null)
terlihat seperti ini:
{ $$typeof: REACT_ELEMENT_TYPE, type: App, key: null, ref: null, props: {}, _owner: null, }
Selain itu, dalam mode dev, kita akan memiliki bidang tambahan yang akan digunakan untuk menampilkan tumpukan yang indah dengan nama file dan baris:
_source: { fileName: "/Users/appleseed/react-example/src/index.js", lineNumber: 7 }

Untuk meringkas sedikit dari apa yang kita lihat di atas. Paket react
bertindak sebagai penerjemah antara kami dan paket lain yang bekerja lebih lanjut pada aplikasi kami, menerjemahkan panggilan kami ke dalam kata-kata yang dapat dimengerti, misalnya, ke rekonsiliator.
React.useState
Di versi 16.8, kait muncul. Apa itu dan bagaimana menggunakannya Anda dapat membaca tautannya , tetapi sekarang kita lihat apa yang ada dalam paket react
.
Faktanya, tidak banyak yang bisa dikatakan. Intinya, sebuah paket adalah fasad yang melaluinya tantangan kita menuju ke entitas internal.
Jadi, useState
tidak lebih dari dua baris kode:
export function useState<S>(initialState: (() => S) | S) { const dispatcher = resolveDispatcher(); return dispatcher.useState(initialState); }
Kait yang tersisa terlihat hampir identik. Di sini kita mendapatkan dispatcher saat ini, yang merupakan objek dan berisi bidang, misalnya useState
. Operator ini berubah tergantung pada apakah kami memiliki render pertama sekarang atau kami hanya ingin memperbarui komponen.
Implementasi hook yang sebenarnya disimpan dalam paket react-reconciler
, yang akan kita bahas di salah satu artikel berikut.
Apa selanjutnya
Satu hal lagi. Setelah membaca artikel ini, Anda dapat memahami mengapa kami selalu mengimpor paket reaksi, meskipun kami tidak menggunakannya secara langsung. Ini diperlukan agar setelah mencerna JSX kami dengan gelembung, kami memiliki variabel React
.
Orang-orang dari tim reaksi mengurus ini (dan bukan hanya ini) dan sekarang sedang bekerja untuk mengganti createElement
.
Singkatnya, ada keinginan untuk mengganti metode pembuatan elemen saat ini dengan dua - jsx
dan jsxs
. Ini perlu karena beberapa alasan:
- kami membahas di atas cara kerja
createElement
. Itu terus-menerus menyalin alat peraga dan menambahkan bidang children
- children
ke objek, di mana ia menyimpan anak-anak yang kami berikan sebagai argumen ke fungsi (3 argumen dan lebih lanjut). Sekarang diusulkan untuk melakukan ini pada tahap konversi jsx
ke panggilan javascript
, karena membuat elemen adalah fungsi yang sering disebut dan tidak bebas untuk melakukan modifikasi alat peraga di runtime setiap kali; - Anda dapat menyingkirkan mengimpor objek
React
dan hanya mengimpor fungsi spesifik ( import { jsx } from 'react'
, misalnya) dan, dengan demikian, tidak dapat menambahkan ke majelis apa yang tidak kami gunakan. Selain itu, Anda tidak harus menyelesaikan bidang React
objek React
setiap saat, karena juga tidak gratis; - Kami membahas di atas bahwa kami memiliki kasus khusus ketika kami mengeluarkan
key
dari alat peraga dan meneruskannya lebih lanjut. Sekarang diusulkan untuk mengambil key
dari jsx
pada tahap transpiling dan meneruskannya parameter ketiga ke fungsi pembuatan elemen.
Baca lebih lanjut di sini . Paket react
sudah memiliki jsxs
dan jsxs
. Jika Anda ingin bermain-main dengan ini, Anda dapat mengkloning repositori reaksi, mengatur flag enableJSXTransformAPI
menjadi true
dalam file ReactFeatureFlags.js
dari paket shared
dan mengkompilasi versi reaksi ( yarn build
) dengan API baru yang diaktifkan.
Terakhir
Pada ini saya akan mengakhiri cerita hari ini tentang paket react
dan kali berikutnya kita akan berbicara tentang bagaimana paket react-dom
menggunakan apa yang dibuat oleh react
, dan metode apa serta bagaimana implementasinya.
Terima kasih sudah membaca sampai akhir!