Ketika React.js 16.8 dirilis kami mendapat kesempatan untuk menggunakan React Hooks. Kait membuat kita dapat menulis komponen yang berfungsi penuh menggunakan fungsi. Kita dapat menggunakan semua fitur React.js dan melakukannya dengan cara yang lebih nyaman.
Banyak orang tidak setuju dengan konsepsi Hooks. Dalam artikel ini saya ingin memberi tahu tentang beberapa keuntungan penting yang diberikan React Hooks kepada Anda dan mengapa kami perlu menulis dengan Hooks.
Saya tidak akan berbicara tentang cara menggunakan kait. Itu tidak terlalu penting untuk contoh. Jika Anda ingin membaca sesuatu tentang topik ini, Anda dapat menggunakan dokumentasi resmi . Juga, jika topik ini menarik bagi Anda, saya akan menulis lebih banyak tentang Hooks.
Kait memungkinkan kita menggunakan kembali kode kita dengan mudah
Mari kita bayangkan sebuah komponen yang merender bentuk sederhana. Ini bisa menjadi sesuatu yang menunjukkan beberapa input kepada kami dan memungkinkan kami untuk mengubah nilainya.
Dengan notasi kelas, akan ada sesuatu seperti ini:
class Form extends React.Component { state = { // Fields values fields: {}, }; render() { return ( <form> {/* Inputs render */} </form> ); }; }
Mari kita bayangkan sekarang bahwa kita ingin secara otomatis menyimpan nilai bidang kita ke backend setiap kali mereka berubah. Saya menyarankan untuk melewati definisi fungsi eksternal seperti shallowEqual
dan debounce
.
class Form extends React.Component { constructor(props) { super(props); this.saveToDraft = debounce(500, this.saveToDraft); }; state = { // Fields values fields: {}, // Draft saving meta draft: { isSaving: false, lastSaved: null, }, }; saveToDraft = (data) => { if (this.state.isSaving) { return; } this.setState({ isSaving: true, }); makeSomeAPICall().then(() => { this.setState({ isSaving: false, lastSaved: new Date(), }) }); } componentDidUpdate(prevProps, prevState) { if (!shallowEqual(prevState.fields, this.state.fields)) { this.saveToDraft(this.state.fields); } } render() { return ( <form> {/* Draft saving meta render */} {/* Inputs render */} </form> ); }; }
Komponen yang sama dengan kait:
const Form = () => { // Our state const [fields, setFields] = useState({}); const [draftIsSaving, setDraftIsSaving] = useState(false); const [draftLastSaved, setDraftLastSaved] = useState(false); useEffect(() => { const id = setTimeout(() => { if (draftIsSaving) { return; } setDraftIsSaving(true); makeSomeAPICall().then(() => { setDraftIsSaving(false); setDraftLastSaved(new Date()); }); }, 500); return () => clearTimeout(id); }, [fields]); return ( <form> {/* Draft saving meta render */} {/* Inputs render */} </form> ); }
Seperti yang kita lihat, tidak ada perbedaan besar di sini. Kami mengganti this.state
dengan useState
hook dan menyimpan konsep di useEffect
hook sekarang.
Perbedaan yang ingin saya tunjukkan di sini adalah (ada perbedaan lain juga, tetapi saya akan berkonsentrasi pada yang ini): kita dapat dengan mudah mengekstrak kode ini dari komponen kita dan menggunakannya di tempat lain:
// useDraft hook can be used in any other component const useDraft = (fields) => { const [draftIsSaving, setDraftIsSaving] = useState(false); const [draftLastSaved, setDraftLastSaved] = useState(false); useEffect(() => { const id = setTimeout(() => { if (draftIsSaving) { return; } setDraftIsSaving(true); makeSomeAPICall().then(() => { setDraftIsSaving(false); setDraftLastSaved(new Date()); }); }, 500); return () => clearTimeout(id); }, [fields]); return [draftIsSaving, draftLastSaved]; } const Form = () => { // Our state const [fields, setFields] = useState({}); const [draftIsSaving, draftLastSaved] = useDraft(fields); return ( <form> {/* Draft saving meta render */} {/* Inputs render */} </form> ); }
Dan kita bisa menggunakan hook useDraft
di komponen lain! Tentu saja, ini adalah contoh yang sangat sederhana, tetapi penggunaan kembali kode cukup penting dan contoh ini menunjukkan betapa mudahnya menggunakan Hooks.
Kait memungkinkan kita untuk menulis komponen dengan cara yang lebih intuitif
Mari kita bayangkan rendering komponen kelas, misalnya, layar obrolan, daftar obrolan, dan formulir pesan. Seperti ini:
class ChatApp extends React.Component { state = { currentChat: null, }; handleSubmit = (messageData) => { makeSomeAPICall(SEND_URL, messageData) .then(() => { alert(`Message is sent to chat ${this.state.currentChat}`); }); }; render() { return ( <Fragment> <ChatsList changeChat={currentChat => { this.setState({ currentChat }); }} /> <CurrentChat id={currentChat} /> <MessageForm onSubmit={this.handleSubmit} /> </Fragment> ); }; }
Lalu bayangkan pengguna kami menggunakan komponen obrolan ini:
- Mereka membuka obrolan 1
- Mereka mengirim pesan (bayangkan jaringan yang lambat)
- Mereka membuka obrolan 2
- Mereka melihat peringatan tentang pesan mereka:
- "Pesan dikirim ke obrolan 2"
Tapi mereka mengirim pesan ke obrolan kedua, bagaimana itu terjadi? Itu karena metode kelas bekerja dengan nilai saat ini, bukan nilai yang kami miliki ketika kami memulai permintaan pesan. Ini bukan masalah besar dengan komponen sederhana seperti ini, tetapi dapat menjadi sumber bug dalam sistem yang lebih kompleks.
Di sisi lain, komponen fungsional bertindak dengan cara lain:
const ChatApp = () => { const [currentChat, setCurrentChat] = useState(null); const handleSubmit = useCallback( (messageData) => { makeSomeAPICall(SEND_URL, messageData) .then(() => { alert(`Message is sent to chat ${currentChat}`); }); }, [currentChat] ); render() { return ( <Fragment> <ChatsList changeChat={setCurrentChat} /> <CurrentChat id={currentChat} /> <MessageForm onSubmit={handleSubmit} /> </Fragment> ); }; }
Mari kita bayangkan pengguna kami:
- Mereka membuka obrolan 1
- Mereka mengirim pesan (bayangkan jaringan yang lambat)
- Mereka membuka obrolan 2
- Mereka melihat peringatan tentang pesan mereka:
- "Pesan dikirim ke obrolan 1"
Nah, apa yang berubah? Sekarang kami bekerja dengan sebuah nilai, ditangkap dalam momen render. Kami sedang membuat handleSubmit
baru setiap kali currentChat
berubah. Ini memungkinkan kita untuk melupakan perubahan di masa depan dan berpikir tentang sekarang .
Setiap komponen membuat menangkap semua yang digunakannya .
Kait membuat komponen siklus hidup hilang
Alasan ini sangat bersinggungan dengan yang sebelumnya. React adalah perpustakaan UI deklaratif. Deklaratif membuat UI membuat dan memproses lebih mudah. Ini memungkinkan kita untuk melupakan tentang perubahan DOM penting.
Meski begitu, ketika kita menggunakan kelas, kita menghadapi siklus komponen. Ini terlihat seperti ini:
- Pemasangan
- Memperbarui (setiap kali
state
atau properti berubah) - Lepas
Tampaknya nyaman tetapi saya meyakinkan bahwa itu hanya karena kebiasaan kita. Ini tidak seperti Bereaksi.
Alih-alih ini, komponen fungsional memungkinkan kita untuk menulis kode komponen dan melupakan siklus hidup. Kami hanya memikirkan sinkronisasi . Kami menulis fungsi membuat UI kami dari alat peraga input dan keadaan dalam.
Pada awalnya useEffect
hook seperti penggantian untuk componentDidMount
, componentDidUpdate
dan metode siklus hidup lainnya. Tapi tidak seperti ini. Ketika kami menggunakan useEffect
kami berkata untuk Bereaksi: "Hei, buat ini setelah merender komponen saya".
Berikut adalah contoh yang bagus dari artikel besar tentang useEffect :
- Bereaksi: Beri saya UI ketika negara adalah
0
. - Komponen Anda:
- Inilah hasil rendernya:
<p>You clicked 0 times</p>
. - Ingat juga untuk menjalankan efek ini setelah selesai:
() => { document.title = 'You clicked 0 times' }
.
- Bereaksi: Tentu. Memperbarui UI. Hai browser, saya menambahkan beberapa hal ke DOM.
- Browser: Keren, saya melukisnya di layar.
- Bereaksi: Oke, sekarang saya akan menjalankan efek yang Anda berikan kepada saya.
- Menjalankan
() => { document.title = 'You clicked 0 times' }
.
Itu jauh lebih deklaratif, bukan?
Sebagai penutup
React Hooks memungkinkan kami untuk menyingkirkan beberapa masalah dan membuat pengembangan lebih mudah. Kita hanya perlu mengubah model mental kita. Komponen fungsional sebenarnya adalah fungsi UI dari alat peraga. Mereka menggambarkan bagaimana semua itu harus terjadi kapan saja dan membantu kita melupakan perubahan.
Kita perlu belajar bagaimana menggunakannya, tapi hei, apakah Anda menulis komponen kelas dengan benar pada saat pertama?