Penyatuan komponen visual. Bagian 1. Gaya



Artikel ini terutama bermanfaat bagi pengembang yang tidak bekerja dengan set komponen siap pakai, seperti material-ui, tetapi mengimplementasikannya sendiri. Sebagai contoh, suatu produk telah dikembangkan untuk produk tersebut, yang mencerminkan bagaimana tombol, modal, dll terlihat. Untuk menerapkan dengan benar sistem desain semacam itu, semua atomnya perlu menambahkan dukungan yang baik untuk komposisinya. Dengan kata lain, perlu untuk memastikan bahwa setiap komponen tunggal dapat berintegrasi dan masuk dengan sempurna ke dalam komponen komposit yang lebih besar. Dan jika dia tidak cocok, maka alangkah baiknya memiliki dukungan sederhana untuk penyesuaiannya. Bagaimanapun, ini adalah topik besar yang terpisah, dan mungkin saya akan kembali ke lain waktu.

Lirik


Halo semuanya. Saya memulai perjalanan saya di hub dengan artikel yang sederhana namun bermanfaat. Bagi saya, itu ternyata terlalu rinci, tetapi saya masih mencoba beradaptasi dengan pembaca, dan tidak untuk diri saya sendiri. Sebelum menulis artikel berikutnya (jika ada) pada topik yang lebih kompleks, saya memiliki keinginan untuk menyesuaikan presentasi saya pada umpan balik (jika ada).

Ketentuan yang digunakan:

  • Komponen visual adalah komponen yang mengembalikan elemen yang tertanam dalam DOM. Misalnya, return (<div />) . Komponen yang hanya mengembalikan komponen lain tidak boleh ditafsirkan secara visual.

Pendahuluan


Ketika Anda mengembangkan komponen, Anda tidak dapat membuatnya sepenuhnya universal. Di kepala Anda, Anda selalu mulai dari opsi spesifik untuk penggunaannya. Sering kali ternyata setelah pengembangan, kolega Anda mulai "mendorong komponen ini ke mana saja." Anda marah kepada mereka: “Yah, saya tidak mengembangkannya untuk ini! Itu tidak dimaksudkan untuk tugas ini! " Tentu saja, perbaikan tidak bisa dihindari, dan bahkan perlu. Tapi ini seharusnya bukan perbaikan seperti melempar alat peraga baru untuk meningkatkan indentasi dari 4px menjadi 8px, yang akan digunakan dalam satu atau dua kasus dari lima puluh. Komponen harus memiliki geometri eksternal khusus.

TypeScript, bantu


Pertimbangkan antarmuka, yang artinya harus ditempatkan, misalnya, di src/Library/Controls.ts . Komentar singkat diberikan untuk bidang, di bawah ini kami akan menganalisisnya secara lebih rinci.

 export interface VisualComponentProps { //  .   - children?: React.ReactNode; //    css className?: string; //   ,     . doNotRender?: boolean; //     doNotRender true fallback?: JSX.Element; //    css style?: React.CSSProperties; } 

Ini adalah antarmuka alat peraga komponen. Yang mana Semua komponen visual. Mereka harus diterapkan pada elemen rootnya.

Alat peraga dari setiap komponen visual yang dikembangkan harus diperluas menggunakan antarmuka ini.

Segera perhatikan fakta bahwa semua alat peraga ini opsional. Pertimbangkan mereka.

  • children - children berada di komponen kelas React.Component, komponen komponen React.FC, tetapi mereka tidak dalam fungsi biasa tanpa menentukan pengetikan React.FC. Karena itu, kami memintanya.
  • className/style menggunakan nama yang mirip, seperti pada JSX'nom <div /> yang biasa. Kami tidak memproduksi semantik. Prinsip identitas nama ini digunakan, misalnya, dalam alat peraga untuk menentukan tautan ref .
  • doNotRender digunakan sebagai alternatif untuk kruk menyakitkan dalam rendering JSX berdasarkan kondisi . Menerapkan solusi ini, kita tidak perlu menempatkan kawat gigi dalam metode render, mengganggu pembacaan kode. Bandingkan 2 cuplikan kode:

    Rendering bersyarat perawan:

    App.tsx

     renderComponent() { const {props, state} = this; const needRender = state.something; return ( <PageLayout> <UIButton children={'This is a button'} /> {needRender && <UIButton children={'This is another button'} /> } </PageLayout> ); } 

    Alat peraga Chad doNotRender:

    App.tsx

     renderComponent() { const {props, state} = this; const needRender = state.something; return ( <PageLayout> <UIButton children={'This is a button'} /> <UIButton children={'This is another button'} doNotRender={!needRender} /> </PageLayout> ); } 

    Pada versi pertama, kami meningkatkan level bersarang dari tombol bawah, meskipun dalam arti arti bersarangnya berada pada level yang sama dengan yang teratas. Itu terlihat buruk di editor saya, di mana saya menggunakan tab dengan lebar 2 spasi, dan ini bahkan lebih buruk.

    Pada opsi kedua, kita memiliki penyatuan yang sama, minus doNotRender yang mungkin tidak menarik perhatian dan pengembang tidak akan mengerti apa yang terjadi. Tetapi, jika dalam proyek Anda setiap komponen visual dibuat sesuai dengan prinsip ini, maka masalah ini segera hilang.
  • fallback diperlukan jika kita tidak ingin membuat null dengan doNotRender true , tetapi semacam elemen kustom. Ini digunakan secara analogi dengan React Suspense , karena memiliki arti yang sama (kami tidak menghasilkan semantik)

Saya ingin menunjukkan cara menggunakannya dengan benar. Mari kita buat tombol sederhana.

Catatan: dalam kode di bawah ini saya juga menggunakan css-modules, sass dan classnames.

UIButton.tsx

 import * as React from 'react'; import { VisualComponentProps } from 'Library/Controls'; import * as css from './Button.sass'; import cn from 'classnames'; //  ()  export interface ButtonBasicProps { disabled?: boolean; } export interface ButtonProps extends ButtonBasicProps, VisualComponentProps {} export function UIButton(props: ButtonProps) { //   undefined,     // "Nothing was returned from render." if (props.doNotRender) return props.fallback || null; //      const rootClassNames = cn( // ,   sass css.Button, // ,     props props.className, //      props.disabled && css._disabled ); return ( <div children={props.children} className={rootClassNames} style={props.style} /> ) } 

App.tsx

 renderComponent() { const {props, state} = this; const needRenderSecond = true; return ( <PageLayout> <UIButton children={'This is a button'} style={{marginRight: needRenderSecond ? 5 : null}} /> <UIButton disabled children={'This is another button'} doNotRender={!needRenderSecond} /> </PageLayout> ); } 

Hasil:



Refleksi dan Kesimpulan


Lebih mudah untuk beroperasi dengan komponen seperti divs, membuat berbagai pembungkus, komposisi, spesialisasi, melampaui kerangka fungsi asli yang tertanam di dalamnya .

Dapat dikatakan bahwa karena tidak ada tombol kuning kondisional dalam sistem desain, dan pengembang perlu membuatnya, maka masalahnya bukan pada komponen, tetapi pada kenyataan bahwa kebutuhan ini tercipta. Namun, kenyataannya adalah situasi seperti itu muncul, dan cukup sering. "... Tapi kita harus hidup! Kita harus hidup." Selain itu, prinsip kaskade css tidak selalu dapat dipraktikkan, dan Anda mungkin mengalami kasus ketika gaya Anda hanya tumpang tindih dengan spesifisitas pemilih yang lebih tinggi (atau dijelaskan di atas). Di sini gaya hanya membantu.

Akhirnya, saya akan menambahkan beberapa (secara harfiah) momen.

  1. Perhatikan bahwa doNotRender tidak sepenuhnya mengulangi perilaku rendering bersyarat. Anda juga akan menjalankan metode siklus hidup, cukup render akan mengembalikan fallback atau null. Dalam beberapa komponen kompleks, Anda mungkin ingin menghindari menjalankan metode siklus hidup. Untuk melakukan ini, Anda hanya perlu membuat spesialisasi built-in dari komponen Anda.

    Menggunakan contoh UIButton: ganti nama UIButton menjadi UIButtonInner dan tambahkan kode berikut di bawahnya:

    UIButton.tsx

     export function UIButton(props: ButtonProps) { if (props.doNotRender) return props.fallback || null; return <UIButtonInner {...props} />; } 

    PS Jangan membuat kesalahan panggilan rekursif UIButton dalam fungsi ini!
  2. Dalam kasus yang jarang terjadi ketika gaya pada pembungkus dan pada komponen yang dibungkus dapat berubah secara independen, antarmuka berikut mungkin berguna bagi Anda

    Library/Controls.ts

     export interface VisualComponentWrapperProps extends VisualComponentProps { wrappedVisual?: VisualComponentProps; } 

    Dan penggunaannya
    UIButton.tsx

     interface ButtonSomeWrapperProps extends ButtonBasicProps, VisualComponentWrapperProps { myCustomProp?: number; } export function UIButtonSomeWrapper(props: ButtonSomeWrapperProps) { if (props.doNotRender) return props.fallback || null; const { //  VisualComponentProps  style, className, children, fallback, doNotRender, // VisualComponentProps   wrappedVisual, //    myCustomProp, //     ...uiButtonProps } = props; return ( <div style={style} className={className} > {myCustomProp} <UIButton {...wrappedVisual} {...uiButtonProps} /> {children} </div> ); } 

Mengembangkan aplikasi menggunakan pendekatan ini akan secara signifikan meningkatkan usabilitas komponen Anda, mengurangi jumlah gaya kruk yang tidak perlu (berbicara tentang gaya yang dijelaskan dalam file gaya komponen khusus untuk kebutuhan komponen lain) dan alat peraga, dan menambahkan kode terstruktur. Itu saja. Pada artikel selanjutnya, kita akan mulai memecahkan masalah penggunaan kembali komponen lebih dari segi kode daripada css. Atau saya akan menulis tentang sesuatu yang lebih menarik. Terima kasih atas perhatian anda

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


All Articles