Komponen kecil: apa yang bisa salah? Kami menggunakan prinsip tanggung jawab tunggal

Kami sajikan kepada Anda terjemahan dari artikel oleh Scott Domes, yang diterbitkan di blog.bitsrc.io. Cari tahu di bawah kat mengapa komponen harus sekecil mungkin dan bagaimana prinsip tanggung jawab tunggal mempengaruhi kualitas aplikasi.


Foto Austin Kirk dengan Unsplash

Keuntungan dari sistem komponen Bereaksi (dan perpustakaan serupa) adalah bahwa UI Anda dibagi menjadi beberapa bagian kecil yang mudah dibaca dan digunakan kembali.

Komponen-komponen ini kompak (100-200 baris), yang memungkinkan pengembang lain untuk dengan mudah memahami dan memodifikasinya.

Meskipun komponen, sebagai suatu peraturan, mencoba menjadi lebih pendek, tidak ada batasan yang jelas dan ketat pada panjangnya. Bereaksi tidak akan keberatan jika Anda memutuskan untuk memasukkan aplikasi Anda ke dalam satu komponen yang sangat besar, terdiri dari 3.000 baris.

... tapi itu tidak sepadan. Sebagian besar komponen Anda, kemungkinan besar, sudah terlalu banyak - atau lebih tepatnya, mereka melakukan terlalu banyak fungsi.

Dalam artikel ini saya akan membuktikan bahwa sebagian besar komponen (bahkan dengan panjang 200-line yang biasa) harus ditargetkan lebih sempit. Mereka harus melakukan hanya satu fungsi, dan melakukannya dengan baik. Inilah yang dikatakan Eddie Osmani hebat di sini .

Tip : ketika bekerja di JS, gunakan Bit untuk mengatur, merakit, dan menggunakan kembali komponen sebagai bagian lego. Bit adalah alat yang sangat efektif untuk bisnis ini, ini akan membantu Anda dan tim Anda menghemat waktu dan mempercepat perakitan. Cobalah saja.

Mari kita tunjukkan bagaimana, ketika membuat komponen , ada yang salah .

Aplikasi kami


Bayangkan kita memiliki aplikasi standar untuk blogger. Dan inilah yang ada di layar utama:

class Main extends React.Component { render() { return ( <div> <header> // Header JSX </header> <aside id="header"> // Sidebar JSX </aside> <div id="post-container"> {this.state.posts.map(post => { return ( <div className="post"> // Post JSX </div> ); })} </div> </div> ); } } 

(Contoh ini, seperti banyak contoh selanjutnya, harus dianggap sebagai pseudo-code.)

Ini menampilkan panel atas, sidebar dan daftar posting. Semuanya sederhana.

Karena kita juga perlu mengunduh posting, kita dapat melakukan ini ketika komponen sedang dipasang:

 class Main extends React.Component { state = { posts: [] }; componentDidMount() { this.loadPosts(); } loadPosts() { // Load posts and save to state } render() { // Render code } } 

Kami juga memiliki beberapa logika yang disebut sidebar. Jika pengguna mengklik tombol di panel atas, sisi akan keluar. Anda dapat menutupnya baik dari atas maupun dari panel samping itu sendiri.

 class Main extends React.Component { state = { posts: [], isSidebarOpen: false }; componentDidMount() { this.loadPosts(); } loadPosts() { // Load posts and save to state } handleOpenSidebar() { // Open sidebar by changing state } handleCloseSidebar() { // Close sidebar by changing state } render() { // Render code } } 

Komponen kami menjadi sedikit lebih rumit, tetapi masih mudah dibaca.

Dapat dikatakan bahwa semua bagiannya memiliki satu tujuan: menampilkan halaman utama aplikasi. Jadi kami mengikuti prinsip tanggung jawab tunggal.

Prinsip tanggung jawab tunggal menyatakan bahwa satu komponen harus memenuhi hanya satu fungsi. Jika kita merumuskan ulang definisi yang diambil dari wikipedia.org , ternyata setiap komponen harus bertanggung jawab hanya untuk satu bagian dari fungsionalitas [aplikasi].

Komponen Utama kami memenuhi persyaratan ini. Apa masalahnya?

Berikut adalah rumusan prinsip yang berbeda: setiap [komponen] harus hanya memiliki satu alasan untuk perubahan .

Definisi ini diambil dari buku Robert Martin , Rapid Software Development. Prinsip, contoh, praktik, ” dan itu sangat penting.

Dengan berfokus pada satu alasan untuk mengubah komponen kami, kami dapat membuat aplikasi yang lebih baik, terlebih lagi, akan mudah dikonfigurasikan.

Untuk lebih jelasnya, mari menyulitkan komponen kami.

Komplikasi


Misalkan sebulan setelah komponen Utama diimplementasikan, fitur baru ditugaskan kepada pengembang dari tim kami. Sekarang pengguna akan dapat menyembunyikan posting (misalnya, jika mengandung konten yang tidak pantas).

Ini tidak sulit dilakukan!

 class Main extends React.Component { state = { posts: [], isSidebarOpen: false, postsToHide: [] }; // older methods get filteredPosts() { // Return posts in state, without the postsToHide } render() { return ( <div> <header> // Header JSX </header> <aside id="header"> // Sidebar JSX </aside> <div id="post-container"> {this.filteredPosts.map(post => { return ( <div className="post"> // Post JSX </div> ); })} </div> </div> ); } } 

Rekan kami dengan mudah menangani ini. Dia hanya menambahkan satu metode baru dan satu properti baru. Tak satu pun dari mereka yang melihat daftar pendek perubahan memiliki keberatan.

Beberapa minggu kemudian, fitur lain diumumkan - bilah sisi yang ditingkatkan untuk versi seluler. Alih-alih mengacaukan CSS, pengembang memutuskan untuk membuat beberapa komponen JSX yang hanya akan berjalan di perangkat seluler.

 class Main extends React.Component { state = { posts: [], isSidebarOpen: false, postsToHide: [], isMobileSidebarOpen: false }; // older methods handleOpenSidebar() { if (this.isMobile()) { this.openMobileSidebar(); } else { this.openSidebar(); } } openSidebar() { // Open regular sidebar } openMobileSidebar() { // Open mobile sidebar } isMobile() { // Check if mobile device } render() { // Render method } } 

Perubahan kecil lainnya. Beberapa metode baru dan properti baru.

Dan di sini kita punya masalah. Main masih menjalankan hanya satu fungsi (menampilkan layar utama), tetapi Anda melihat semua metode yang sekarang kita hadapi:

 class Main extends React.Component { state = { posts: [], isSidebarOpen: false, postsToHide: [], isMobileSidebarOpen: false }; componentDidMount() { this.loadPosts(); } loadPosts() { // Load posts and save to state } handleOpenSidebar() { // Check if mobile then open relevant sidebar } handleCloseSidebar() { // Close both sidebars } openSidebar() { // Open regular sidebar } openMobileSidebar() { // Open mobile sidebar } isMobile() { // Check if mobile device } get filteredPosts() { // Return posts in state, without the postsToHide } render() { // Render method } } 

Komponen kami menjadi besar dan besar, sulit dimengerti. Dan dengan perluasan fungsi, situasinya hanya akan memburuk.

Apa yang salah?

Satu-satunya alasan


Mari kita kembali ke definisi prinsip tanggung jawab tunggal: komponen apa pun seharusnya hanya memiliki satu alasan untuk perubahan .

Sebelumnya, kami mengubah cara posting ditampilkan, jadi kami harus mengubah komponen Utama kami. Selanjutnya, kami mengubah cara bilah sisi terbuka - dan sekali lagi kami mengubah komponen Utama.

Komponen ini memiliki banyak alasan untuk perubahan yang tidak terkait. Ini berarti ia melakukan terlalu banyak fungsi .

Dengan kata lain, jika Anda dapat secara signifikan mengubah bagian dari komponen Anda dan ini tidak mengarah pada perubahan di bagian lain itu, maka komponen Anda memiliki terlalu banyak tanggung jawab.

Pemisahan yang lebih efisien


Solusinya sederhana: Anda perlu membagi komponen Utama menjadi beberapa bagian. Bagaimana cara melakukannya?

Mari kita mulai lagi. Render layar utama tetap menjadi tanggung jawab komponen Utama, tetapi kami menguranginya hanya untuk menampilkan komponen terkait:

 class Main extends React.Component { render() { return ( <Layout> <PostList /> </Layout> ); } } 

Bagus

Jika kami tiba-tiba mengubah tata letak layar utama (misalnya, menambahkan bagian tambahan), maka Utama juga akan berubah. Dalam kasus lain, kita tidak punya alasan untuk menyentuhnya. Bagus

Mari beralih ke Layout :

 class Layout extends React.Component { render() { return ( <SidebarDisplay> {(isSidebarOpen, toggleSidebar) => ( <div> <Header openSidebar={toggleSidebar} /> <Sidebar isOpen={isSidebarOpen} close={toggleSidebar} /> </div> )} </SidebarDisplay> ); } } 

Ini sedikit lebih rumit. Layout bertanggung jawab untuk merender komponen tata letak (panel samping / panel atas). Tetapi kami tidak akan menyerah pada godaan dan memberikan Layout tanggung jawab untuk menentukan apakah bilah samping terbuka atau tidak.

Kami menetapkan fungsi ini ke komponen SidebarDisplay , yang meneruskan metode atau status yang diperlukan ke komponen Header dan Sidebar .

(Contoh di atas adalah contoh dari Render Props melalui pola Children in React. Jika Anda tidak mengenalnya, jangan khawatir. Penting bahwa ada komponen terpisah yang mengontrol keadaan buka / tutup bilah samping.)

Dan kemudian, Sidebar itu sendiri bisa sangat sederhana jika hanya bertanggung jawab untuk merender sidebar di sebelah kanan.

 class Sidebar extends React.Component { isMobile() { // Check if mobile } render() { if (this.isMobile()) { return <MobileSidebar />; } else { return <DesktopSidebar />; } } } 

Sekali lagi, kami menahan godaan untuk memasukkan JSX untuk komputer / perangkat seluler langsung ke komponen ini, karena dalam hal ini akan ada dua alasan untuk perubahan.

Mari kita lihat komponen lain:

 class PostList extends React.Component { state = { postsToHide: [] } filterPosts(posts) { // Show posts, minus hidden ones } hidePost(post) { // Save hidden post to state } render() { return ( <PostLoader> { posts => this.filterPosts(posts).map(post => <Post />) } </PostLoader> ) } } 

PostList hanya berubah jika kita mengubah cara daftar posting PostList . Tampak jelas, bukan? Inilah yang kita butuhkan.

PostLoader hanya berubah jika kita mengubah cara posting dimuat. Dan akhirnya, Post perubahan hanya jika kami mengubah cara pengiriman pos.

Kesimpulan


Semua komponen ini kecil dan melakukan satu fungsi kecil. Alasan untuk perubahan di dalamnya mudah diidentifikasi, dan komponen itu sendiri diuji dan diperbaiki.

Sekarang aplikasi kita jauh lebih mudah untuk dimodifikasi - mengatur ulang komponen, menambah yang baru dan memperluas fungsionalitas yang ada. Anda hanya perlu melihat file komponen untuk menentukan untuk apa file itu.

Kami tahu bahwa komponen kami akan berubah dan tumbuh seiring waktu, tetapi menerapkan aturan universal ini akan membantu Anda menghindari utang teknis dan meningkatkan kecepatan tim. Cara mendistribusikan komponen terserah Anda, tetapi ingat - hanya ada satu alasan untuk mengubah komponen .

Terima kasih atas perhatian Anda dan nantikan komentar Anda!

Source: https://habr.com/ru/post/id437504/


All Articles