React API yang Berguna Untuk Membangun Komponen Fleksibel Dengan TypeScript

Diterbitkan: 2022-03-10
Ringkasan cepat React with JSX adalah alat yang fantastis untuk membuat komponen yang mudah digunakan. Komponen TypeScript menjadikannya kesenangan mutlak bagi pengembang untuk mengintegrasikan komponen Anda ke dalam aplikasi mereka dan menjelajahi API Anda. Pelajari tentang tiga API React yang kurang dikenal yang dapat membawa komponen Anda ke level berikutnya, dan membantu Anda membangun Komponen React yang lebih baik lagi di artikel ini.

Pernahkah Anda menggunakan React.createElement secara langsung? Bagaimana dengan React.cloneElement ? React lebih dari sekadar mengubah JSX Anda menjadi HTML. Lebih banyak lagi, dan untuk membantu Anda meningkatkan pengetahuan Anda tentang API yang kurang dikenal (tetapi sangat berguna) yang disertakan dengan library React. Kami akan membahas beberapa di antaranya dan beberapa kasus penggunaannya yang dapat secara drastis meningkatkan integrasi dan kegunaan komponen Anda.

Dalam artikel ini, kita akan membahas beberapa React API yang berguna yang tidak begitu umum diketahui tetapi sangat berguna untuk pengembang web. Pembaca harus berpengalaman dengan sintaks React dan JSX, pengetahuan TypeScript sangat membantu tetapi tidak perlu. Pembaca akan pergi dengan semua yang perlu mereka ketahui untuk meningkatkan komponen React saat menggunakannya dalam aplikasi React.

React.cloneElement

Sebagian besar pengembang mungkin belum pernah mendengar tentang cloneElement atau pernah menggunakannya. Itu relatif baru diperkenalkan untuk menggantikan fungsi cloneWithProps yang sekarang sudah tidak digunakan lagi. cloneElement sebuah elemen, itu juga memungkinkan Anda menggabungkan props baru dengan elemen yang ada, memodifikasinya atau menimpanya sesuai keinginan Anda. Ini membuka opsi yang sangat kuat untuk membangun API kelas dunia untuk komponen fungsional. Perhatikan tanda tangan.

 function cloneElement( element, props?, ...children)

Inilah versi TypeScript yang diringkas:

 function cloneElement( element: ReactElement, props?: HTMLAttributes, ...children: ReactNode[]): ReactElement

Anda dapat mengambil sebuah elemen, memodifikasinya, bahkan menimpa anak-anaknya, dan kemudian mengembalikannya sebagai elemen baru. Perhatikan contoh berikut. Katakanlah kita ingin membuat komponen Tautan TabBar . Itu mungkin terlihat seperti ini.

 export interface ITabbarProps { links: {title: string, url: string}[] } export default function Tabbar(props: ITabbarProps) { return ( <> {props.links.map((e, i) => <a key={i} href={e.url}>{e.title}</a> )} </> ) }

TabBar adalah daftar tautan, tetapi kita membutuhkan cara untuk mendefinisikan dua bagian data, judul tautan, dan URL. Jadi kami ingin struktur data diteruskan dengan informasi ini. Jadi pengembang kami akan membuat komponen kami seperti itu.

 function App() { return ( <Tabbar links={[ {title: 'First', url: '/first'}, {title: 'Second', url: '/second'}] } /> ) }

Ini bagus, tetapi bagaimana jika pengguna ingin merender elemen button alih-alih a ? Nah, kita bisa menambahkan properti lain yang memberi tahu komponen jenis elemen apa yang akan dirender.

Tetapi Anda dapat melihat bagaimana ini akan menjadi berat dengan cepat, kami perlu mendukung lebih banyak properti untuk menangani berbagai kasus penggunaan dan kasus tepi untuk fleksibilitas maksimum.

Inilah cara yang lebih baik, menggunakan React.cloneElement .

Kita akan mulai dengan mengubah antarmuka kita untuk mereferensikan tipe ReactNode . Ini adalah tipe generik yang mencakup apa pun yang dapat dirender oleh React, biasanya Elemen JSX tetapi juga dapat berupa string dan bahkan null . Ini berguna untuk menunjuk Anda agar mau menerima komponen React atau JSX sebagai argumen sebaris.

 export interface ITabbarProps { links: ReactNode[] }

Sekarang kami meminta pengguna untuk memberi kami beberapa Elemen React, dan kami akan merendernya seperti yang kami inginkan.

 function Tabbar(props: ITabbarProps) { return ( <> {props.links.map((e, i) => e // simply return the element itself )} </> ) }

Ini benar-benar valid dan akan membuat elemen kita. Tapi kita melupakan beberapa hal. Salah satunya, key ! Kami ingin menambahkan kunci sehingga Bereaksi dapat membuat daftar kami secara efisien. Kami juga ingin mengubah elemen kami untuk membuat transformasi yang diperlukan sehingga cocok dengan gaya kami, seperti className , dan seterusnya.

Kita dapat melakukannya dengan React.cloneElement , dan fungsi lain React.isValidElement untuk memeriksa apakah argumen sesuai dengan apa yang kita harapkan!

Lebih banyak setelah melompat! Lanjutkan membaca di bawah ini

React.isValidElement

Fungsi ini mengembalikan nilai true jika suatu elemen adalah Elemen React yang valid dan React dapat merendernya. Berikut adalah contoh memodifikasi elemen dari contoh sebelumnya.

 function Tabbar(props: ITabbarProps) { return ( <> {props.links.map((e, i) => isValidElement(e) && cloneElement(e, {key: `${i}`, className: 'bold'}) )} </> ) }

Di sini kami menambahkan penyangga utama ke setiap elemen yang kami lewati dan membuat setiap tautan dicetak tebal pada saat yang bersamaan! Kami sekarang dapat menerima Elemen Bereaksi sewenang-wenang sebagai alat peraga seperti:

 function App() { return ( <Tabbar links={[ <a href='/first'>First</a>, <button type='button'>Second</button> ]} /> ) }

Kita dapat mengganti salah satu props yang dipasang pada sebuah elemen, dan dengan mudah menerima berbagai macam elemen yang membuat komponen kita jauh lebih fleksibel dan mudah digunakan.

Keuntungannya di sini adalah jika kita ingin mengatur handler onClick kustom ke tombol kita, kita bisa melakukannya. Menerima elemen React sendiri sebagai argumen adalah cara yang ampuh untuk memberikan fleksibilitas pada desain komponen Anda.

useState Fungsi Penyetel Status

Gunakan Kait! Kait useState sangat berguna dan API yang fantastis untuk membangun status dengan cepat ke dalam komponen Anda seperti:

 const [myValue, setMyValue] = useState()

Karena runtime JavaScript, ini dapat menyebabkan beberapa cegukan. Ingat penutupan?

Dalam situasi tertentu, sebuah variabel mungkin bukan nilai yang benar karena konteksnya, seperti dalam for-loop secara umum atau peristiwa asinkron. Ini karena pelingkupan leksikal. Ketika fungsi baru dibuat, lingkup leksikal dipertahankan. Karena tidak ada fungsi baru, cakupan leksikal newVal tidak dipertahankan, sehingga nilai sebenarnya direferensikan pada saat digunakan.

 setTimeout(() => { setMyValue(newVal) // this will not work }, 1000)

Yang perlu Anda lakukan adalah memanfaatkan setter sebagai fungsi. Dengan membuat fungsi baru, referensi variabel dipertahankan dalam lingkup leksikal dan currentVal dilewatkan oleh React useState Hook itu sendiri.

 setTimeout(() => { setMyValue((currentVal) => { return newVal }) }, 1000)

Ini akan memastikan bahwa nilai Anda diperbarui dengan benar karena fungsi penyetel dipanggil dalam konteks yang benar. Apa yang React lakukan di sini adalah memanggil fungsi Anda dalam konteks yang benar agar pembaruan status React terjadi. Ini juga dapat digunakan dalam situasi lain di mana berguna untuk bertindak berdasarkan nilai saat ini, React memanggil fungsi Anda dengan argumen pertama sebagai nilai saat ini.

Catatan : Untuk bacaan tambahan tentang topik asinkron dan penutupan, saya sarankan membaca " Inisialisasi Lazy useState Dan Pembaruan Fungsi" oleh Kent C. Dodds.

Fungsi Sebaris BEJ

Berikut adalah demo Codepen dari fungsi inline JSX:

Lihat Pena [Hello World in React](https://codepen.io/smashingmag/pen/QWgQQKR) oleh Gaurav Khanna.

Lihat Pena Hello World di React oleh Gaurav Khanna.

Bukan React API per-katakan.

JSX mendukung fungsi inline dan dapat sangat berguna untuk mendeklarasikan logika sederhana dengan variabel inline, selama ia mengembalikan Elemen JSX.

Berikut ini contohnya:

 function App() { return ( <> {(() => { const darkMode = isDarkMode() if (darkMode) { return ( <div className='dark-mode'></div> ) } else { return ( <div className='light-mode'></div> ) // we can declare JSX anywhere! } })()} // don't forget to call the function! </> ) }

Di sini kita mendeklarasikan kode di dalam JSX, kita dapat menjalankan kode arbitrer dan yang harus kita lakukan adalah mengembalikan fungsi JSX yang akan dirender.

Kita dapat membuatnya bersyarat, atau hanya melakukan beberapa logika. Perhatikan tanda kurung yang mengelilingi fungsi sebaris. Juga khususnya di sini di mana kita memanggil fungsi ini, kita bahkan dapat meneruskan argumen ke dalam fungsi ini dari konteks sekitarnya jika kita mau!

 })()}

Ini dapat berguna dalam situasi di mana Anda ingin bertindak pada struktur data kumpulan dengan cara yang lebih kompleks daripada yang diizinkan oleh .map standar di dalam elemen JSX.

 function App() { return ( <> {(() => { let str = '' for (let i = 0; i < 10; i++) { str += i } return (<p>{str}</p>) })()} </> ) }

Di sini kita dapat menjalankan beberapa kode untuk mengulang serangkaian angka dan kemudian menampilkannya sebaris. Jika Anda menggunakan generator situs statis seperti Gatsby, langkah ini juga akan dihitung sebelumnya.

component extends type

Sangat berguna untuk membuat komponen ramah pelengkapan otomatis, fitur ini memungkinkan Anda membuat komponen yang memperluas HTMLElements yang ada atau komponen lainnya. Sebagian besar berguna untuk mengetik dengan benar antarmuka elemen di TypeScript tetapi aplikasi sebenarnya sama untuk JavaScript.

Berikut adalah contoh sederhana, katakanlah kita ingin menimpa satu atau dua properti dari elemen button , tetapi tetap memberikan opsi kepada pengembang untuk menambahkan properti lain ke tombol. Seperti pengaturan type='button' atau type='submit' . Kami jelas tidak ingin membuat ulang seluruh elemen tombol, kami hanya ingin memperluas properti yang ada, dan mungkin menambahkan satu prop lagi.

 import React, { ButtonHTMLAttributes } from 'react'

Pertama kita mengimpor React dan kelas ButtonHTMLAttributes , sebuah tipe yang mencakup props dari HTMLButtonElement . Anda dapat membaca kode sumber untuk jenis antarmuka ini di sini:

Dan Anda dapat melihat tim React telah mengimplementasikan ulang semua API web di TypeScript sehingga dapat diperiksa jenisnya.

Selanjutnya, kami mendeklarasikan antarmuka kami seperti itu, menambahkan properti status kami.

 interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> { status?: 'primary' | 'info' | 'danger' }

Dan akhirnya, kami melakukan beberapa hal. Kami menggunakan ES6 destructuring untuk mengeluarkan props yang kami pedulikan ( status , dan children ) , dan mendeklarasikan properti lainnya sebagai rest . Dan dalam output JSX kami, kami mengembalikan elemen tombol, dengan penataan ES6 untuk menambahkan properti tambahan apa pun ke elemen ini.

 function Button(props: ButtonProps) { const { status, children, ...rest } = props // rest has any other props return ( <button className={`${status}`} {...rest} // we pass the rest of the props back into the element > {children} </button> ) }

Jadi sekarang pengembang dapat menambahkan prop type atau prop lain yang biasanya dimiliki tombol. Kami telah memberikan prop tambahan yang telah kami gunakan di className untuk mengatur gaya tombol.

Inilah seluruh contoh:

 import React, { ButtonHTMLAttributes } from 'react' export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> { status?: 'primary' | 'info' | 'danger' } export default function Button(props: ButtonProps) { const { status, children, ...rest } = props return ( <button className={`${status}`} {...rest} > {children} </button> ) }

Ini merupakan cara yang bagus untuk membuat komponen internal yang dapat digunakan kembali yang sesuai dengan pedoman gaya Anda tanpa membangun kembali seluruh elemen HTML! Anda cukup mengganti seluruh alat peraga seperti mengatur className berdasarkan status atau mengizinkan nama kelas tambahan untuk diteruskan juga.

 import React, { ButtonHTMLAttributes } from 'react' export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> { status?: 'primary' | 'info' | 'danger' } export default function Button(props: ButtonProps) { const { status, children, className, ...rest } = props return ( <button className={`${status || ''} ${className || ''}`} {...rest} > {children} </button> ) }

Di sini kita mengambil prop className yang diteruskan ke elemen Button kita, dan memasukkannya kembali, dengan pemeriksaan keamanan jika prop menjadi undefined .

Kesimpulan

Bereaksi adalah perpustakaan yang sangat kuat, dan ada alasan bagus mengapa itu dengan cepat mendapatkan popularitas. Ini memberi Anda seperangkat alat yang hebat untuk membangun aplikasi web yang berkinerja dan mudah dirawat. Ini sangat fleksibel dan sekaligus sangat ketat, yang bisa sangat berguna jika Anda tahu cara menggunakannya. Ini hanyalah beberapa API yang patut diperhatikan dan sebagian besar diabaikan. Cobalah mereka di proyek Anda berikutnya!

Untuk bacaan lebih lanjut tentang React API terbaru, hook, saya akan merekomendasikan membaca useHooks(). TypeScript Cheatsheet juga memiliki beberapa informasi bagus untuk React dan TypeScript Hooks.