Cara Menggunakan Komponen Bergaya di React

Diterbitkan: 2022-03-10
Ringkasan cepat Meskipun pendekatan berbasis komponen telah mengantarkan batas baru dalam cara kami membangun aplikasi web, itu bukan tanpa ketidaksempurnaannya — salah satunya adalah kegunaan dan skalabilitasnya dengan CSS. Ini telah melahirkan cara baru untuk membangun dan mengelola gaya kita dengan cara khusus komponen , atau dikenal sebagai CSS-in-JS.

Komponen gaya adalah alat CSS-in-JS yang menjembatani kesenjangan antara komponen dan gaya, menawarkan banyak fitur untuk membuat Anda siap dan menjalankan komponen gaya dengan cara yang fungsional dan dapat digunakan kembali. Dalam artikel ini, Anda akan mempelajari dasar-dasar komponen gaya dan cara menerapkannya dengan benar ke aplikasi React Anda. Anda seharusnya telah mengerjakan React sebelumnya sebelum melalui tutorial ini. Jika Anda mencari berbagai opsi dalam menata komponen React, Anda dapat melihat posting kami sebelumnya tentang subjek ini.

Inti dari CSS adalah kemampuan untuk menargetkan elemen HTML apa pun — secara global — tidak peduli posisinya di pohon DOM. Ini bisa menjadi penghalang saat digunakan dengan komponen, karena komponen menuntut, sampai batas tertentu, colocation (yaitu menjaga aset seperti status dan gaya) lebih dekat ke tempat mereka digunakan (dikenal sebagai lokalisasi).

Dalam kata-kata React sendiri, komponen yang ditata adalah “ primitif visual untuk komponen ”, dan tujuannya adalah untuk memberi kita cara yang fleksibel untuk menata komponen. Hasilnya adalah sambungan yang erat antara komponen dan gayanya.

Catatan: Komponen yang diberi gaya tersedia untuk React dan React Native, dan meskipun Anda pasti harus memeriksa panduan React Native, fokus kami di sini adalah pada komponen yang ditata untuk React.

Lebih banyak setelah melompat! Lanjutkan membaca di bawah ini

Mengapa Komponen Bergaya?

Selain membantu Anda menentukan gaya cakupan, komponen gaya mencakup fitur berikut:

  • Awalan vendor otomatis
    Anda dapat menggunakan properti CSS standar, dan komponen bergaya akan menambahkan awalan vendor jika diperlukan.
  • Nama kelas yang unik
    Komponen yang ditata tidak tergantung satu sama lain, dan Anda tidak perlu khawatir tentang namanya karena perpustakaan menanganinya untuk Anda.
  • Penghapusan gaya mati
    Komponen yang diberi gaya menghapus gaya yang tidak digunakan, meskipun dideklarasikan dalam kode Anda.
  • dan masih banyak lagi.

Instalasi

Memasang komponen bergaya itu mudah. Anda dapat melakukannya melalui CDN atau dengan manajer paket seperti Yarn…

 yarn add styled-components

… atau npm:

 npm i styled-components

Demo kami menggunakan create-react-app.

Memulai

Mungkin hal pertama yang Anda perhatikan tentang komponen yang ditata adalah sintaksnya, yang bisa menakutkan jika Anda tidak memahami keajaiban di balik komponen yang ditata. Singkatnya, komponen bergaya menggunakan literal templat JavaScript untuk menjembatani kesenjangan antara komponen dan gaya. Jadi, saat Anda membuat komponen bergaya, yang sebenarnya Anda buat adalah komponen Bereaksi dengan gaya. Ini terlihat seperti ini:

 import styled from "styled-components"; // Styled component named StyledButton const StyledButton = styled.button` background-color: black; font-size: 32px; color: white; `; function Component() { // Use it like any other component. return <StyledButton> Login </StyledButton>; }

Di sini, StyledButton adalah komponen yang ditata, dan itu akan dirender sebagai tombol HTML dengan gaya yang ada. styled adalah metode utilitas internal yang mengubah gaya dari JavaScript menjadi CSS sebenarnya.

Dalam HTML dan CSS mentah, kita akan memiliki ini:

 button { background-color: black; font-size: 32px; color: white; } <button> Login </button>

Jika komponen yang ditata adalah komponen Bereaksi, dapatkah kita menggunakan alat peraga? Ya kita bisa.

Beradaptasi Berdasarkan Alat Peraga

Komponen yang diberi gaya bersifat fungsional , sehingga kita dapat dengan mudah menata elemen secara dinamis. Mari kita asumsikan kita memiliki dua jenis tombol di halaman kita, satu dengan latar belakang hitam, dan yang lainnya biru. Kita tidak harus membuat dua komponen gaya untuk mereka; kita dapat menyesuaikan gaya mereka berdasarkan alat peraga mereka.

 import styled from "styled-components"; const StyledButton = styled.button` min-width: 200px; border: none; font-size: 18px; padding: 7px 10px; /* The resulting background color will be based on the bg props. */ background-color: ${props => props.bg === "black" ? "black" : "blue"; `; function Profile() { return ( <div> <StyledButton bg="black">Button A</StyledButton> <StyledButton bg="blue">Button B</StyledButton> </div> ) }

Karena StyledButton adalah komponen React yang menerima props, kita dapat menetapkan warna latar belakang yang berbeda berdasarkan keberadaan atau nilai dari bg prop.

Namun, Anda akan melihat bahwa kami belum memberi tombol kami type . Mari kita lakukan itu:

 function Profile() { return ( <> <StyledButton bg="black" type="button"> Button A </StyledButton> <StyledButton bg="blue" type="submit" onClick={() => alert("clicked")}> Button B </StyledButton> </> ); }

Komponen gaya dapat membedakan antara jenis alat peraga yang mereka terima. Mereka tahu bahwa type adalah atribut HTML, jadi mereka benar-benar merender <button type="button">Button A</button> , saat menggunakan bg prop dalam pemrosesan mereka sendiri. Perhatikan bagaimana kami juga memasang event handler?

Berbicara tentang atribut, sintaks yang diperluas memungkinkan kita mengelola props menggunakan konstruktor attrs . Lihat ini:

 const StyledContainer = styled.section.attrs((props) => ({ width: props.width || "100%", hasPadding: props.hasPadding || false, }))` --container-padding: 20px; width: ${(props) => props.width}; // Falls back to 100% padding: ${(props) => (props.hasPadding && "var(--container-padding)") || "none"}; `;

Perhatikan bagaimana kita tidak membutuhkan ternary saat mengatur lebar? Itu karena kita sudah menyetel defaultnya dengan width: props.width || "100%", width: props.width || "100%", . Selain itu, kami menggunakan properti khusus CSS karena kami bisa!

Catatan: Jika komponen yang di-style adalah komponen React, dan kita dapat melewatkan props, apakah kita juga dapat menggunakan status? Akun GitHub perpustakaan memiliki masalah dalam menangani masalah ini.

Memperluas Gaya

Katakanlah Anda sedang mengerjakan halaman arahan, dan Anda telah mengatur wadah Anda ke lebar maksimum tertentu untuk menjaga semuanya tetap terpusat. Anda memiliki StyledContainer untuk itu:

 const StyledContainer = styled.section` max-width: 1024px; padding: 0 20px; margin: 0 auto; `;

Kemudian, Anda menemukan bahwa Anda memerlukan wadah yang lebih kecil, dengan bantalan 10 piksel di kedua sisi, bukan 20 piksel. Pikiran pertama Anda mungkin untuk membuat komponen gaya lain, dan Anda benar, tetapi itu tidak akan memakan waktu lama sebelum Anda menyadari bahwa Anda menduplikasi gaya.

 const StyledContainer = styled.section` max-width: 1024px; padding: 0 20px; margin: 0 auto; `; const StyledSmallContainer = styled.section` max-width: 1024px; padding: 0 10px; margin: 0 auto; `;

Sebelum Anda melanjutkan dan membuat StyledSmallContainer , seperti dalam cuplikan di atas, mari pelajari cara menggunakan kembali dan mewarisi gaya. Kurang lebih seperti cara kerja operator spread :

 const StyledContainer = styled.section` max-width: 1024px; padding: 0 20px; margin: 0 auto; `; // Inherit StyledContainer in StyledSmallConatiner const StyledSmallContainer = styled(StyledContainer)` padding: 0 10px; `; function Home() { return ( <StyledContainer> <h1>The secret is to be happy</h1> </StyledContainer> ); } function Contact() { return ( <StyledSmallContainer> <h1>The road goes on and on</h1> </StyledSmallContainer> ); }

Di StyledSmallContainer , Anda akan mendapatkan semua gaya dari StyledContainer , tetapi padding akan diganti. Ingatlah bahwa, biasanya, Anda akan mendapatkan elemen bagian yang dirender untuk StyledSmallContainer , karena itulah yang dirender oleh StyledContainer . Tapi itu tidak berarti itu diukir di batu atau tidak bisa diubah.

Prop Polimorfik "sebagai"

Dengan prop as polimorfik, Anda dapat menukar elemen akhir yang dirender. Salah satu kasus penggunaan adalah ketika Anda mewarisi gaya (seperti pada contoh terakhir). Jika, misalnya, Anda lebih memilih div daripada section untuk StyledSmallContainer , Anda dapat meneruskan as prop ke komponen gaya Anda dengan nilai elemen pilihan Anda, seperti:

 function Home() { return ( <StyledContainer> <h1>It's business, not personal</h1> </StyledContainer> ); } function Contact() { return ( <StyledSmallContainer as="div"> <h1>Never dribble when you can pass</h1> </StyledSmallContainer> ); }

Sekarang, StyledSmallContainer akan dirender sebagai div . Anda bahkan dapat memiliki komponen khusus sebagai nilai Anda:

 function Home() { return ( <StyledContainer> <h1>It's business, not personal</h1> </StyledContainer> ); } function Contact() { return ( <StyledSmallContainer as={StyledContainer}> <h1>Never dribble when you can pass</h1> </StyledSmallContainer> ); }

Jangan anggap remeh.

Sintaks Seperti SCSS

Stylis praprosesor CSS memungkinkan komponen bergaya untuk mendukung sintaks seperti SCSS, seperti bersarang:

 const StyledProfileCard = styled.div` border: 1px solid black; > .username { font-size: 20px; color: black; transition: 0.2s; &:hover { color: red; } + .dob { color: grey; } } `; function ProfileCard() { return ( <StyledProfileCard> <h1 className="username">John Doe</h1> <p className="dob"> Date: <span>12th October, 2013</span> </p> <p className="gender">Male</p> </StyledProfileCard> ); }

Animasi

Komponen yang diberi gaya memiliki pembantu keyframes yang membantu membuat keyframe animasi (dapat digunakan kembali). Keuntungannya di sini adalah bahwa keyframe akan terlepas dari komponen yang ditata dan dapat diekspor dan digunakan kembali di mana pun dibutuhkan.

 import styled, {keyframes} from "styled-components"; const slideIn = keyframes` from { opacity: 0; } to { opacity: 1; } `; const Toast = styled.div` animation: ${slideIn} 0.5s cubic-bezier(0.4, 0, 0.2, 1) both; border-radius: 5px; padding: 20px; position: fixed; `;

Gaya Global

Sementara tujuan awal CSS-in-JS dan, dengan ekstensi, komponen gaya adalah pelingkupan gaya, kami juga dapat memanfaatkan gaya global komponen gaya. Karena kami sebagian besar bekerja dengan gaya tercakup, Anda mungkin berpikir itu adalah pengaturan pabrik yang tidak berubah-ubah, tetapi Anda salah. Pikirkan tentang hal ini: Apa sebenarnya pelingkupan itu? Secara teknis mungkin bagi kami — atas nama gaya global — untuk melakukan sesuatu yang mirip dengan ini:

 ReactDOM.render( <StyledApp> <App /> </StyledApp>, document.getElementById("root") );

Tapi kita sudah memiliki fungsi pembantu — createGlobalStyle — yang satu-satunya alasan keberadaannya adalah gaya global. Jadi, mengapa menyangkal tanggung jawabnya?

Satu hal yang dapat kita gunakan untuk createGlobalStyle adalah menormalkan CSS:

 import {createGlobalStyle} from "styled-components"; const GlobalStyle = createGlobalStyle` /* Your css reset here */ `; // Use your GlobalStyle function App() { return ( <div> <GlobalStyle /> <Routes /> </div> ); }

Catatan: Gaya yang dibuat dengan createGlobalStyle tidak menerima turunan apa pun. Pelajari lebih lanjut di dokumentasi.

Pada titik ini, Anda mungkin bertanya-tanya mengapa kita harus repot-repot menggunakan createGlobalStlye sama sekali. Berikut adalah beberapa alasannya:

  • Kami tidak dapat menargetkan apa pun di luar render root tanpanya (misalnya, html , body , dll.).
  • createGlobalStyle menyuntikkan gaya tetapi tidak membuat elemen aktual apa pun. Jika Anda melihat contoh terakhir dengan cermat, Anda akan melihat bahwa kami tidak menentukan elemen HTML apa pun untuk dirender. Ini keren karena kita mungkin tidak benar-benar membutuhkan elemen tersebut. Lagi pula, kami prihatin dengan gaya global. Kami menargetkan pemilih secara luas, bukan elemen tertentu.
  • createGlobalStyle tidak tercakup dan dapat dirender di mana saja di aplikasi kami dan akan berlaku selama itu di DOM. Pikirkan konsepnya , bukan strukturnya .
 import {createGlobalStyle} from "styled-components"; const GlobalStyle = createGlobalStyle` /* Your css reset here */ .app-title { font-size: 40px; } `; const StyledNav = styled.nav` /* Your styles here */ `; function Nav({children}) { return ( <StyledNav> <GlobalStyle /> {children} </StyledNav> ); } function App() { return ( <div> <Nav> <h1 className="app-title">STYLED COMPONENTS</h1> </Nav> <Main /> <Footer /> </div> ); }

Jika Anda memikirkan strukturnya, maka app-title tidak boleh ditata seperti yang diatur dalam GlobalStyle . Tapi itu tidak bekerja seperti itu. Di mana pun Anda memilih untuk merender GlobalStyle Anda, itu akan disuntikkan saat komponen Anda dirender .

Hati-hati : createGlobalStyles hanya akan dirender jika dan saat berada di DOM.

Pembantu CSS

Kita sudah melihat bagaimana mengadaptasi gaya berdasarkan alat peraga. Bagaimana jika kita ingin melangkah lebih jauh? Fungsi pembantu CSS membantu untuk mencapai hal ini. Mari kita asumsikan kita memiliki dua bidang input teks dengan status: kosong dan aktif, masing-masing dengan warna berbeda. Kita bisa melakukan ini:

 const StyledTextField = styled.input` color: ${(props) => (props.isEmpty ? "none" : "black")}; `;

Semua baik-baik saja. Selanjutnya, jika kita perlu menambahkan status terisi lainnya, kita harus memodifikasi gaya kita:

 const StyledTextField = styled.input` color: ${(props) => props.isEmpty ? "none" : props.active ? "purple" : "blue"}; `;

Sekarang operasi ternary semakin kompleks. Bagaimana jika nanti kita menambahkan status lain ke bidang input teks? Atau bagaimana jika kita ingin memberi setiap negara bagian gaya tambahan, selain warna? Dapatkah Anda membayangkan gaya kram ke dalam operasi ternary? css sangat berguna.

 const StyledTextField = styled.input` width: 100%; height: 40px; ${(props) => (props.empty && css` color: none; backgroundcolor: white; `) || (props.active && css` color: black; backgroundcolor: whitesmoke; `)} `;

Apa yang telah kami lakukan adalah semacam memperluas sintaks ternary kami untuk mengakomodasi lebih banyak gaya, dan dengan sintaks yang lebih mudah dipahami dan terorganisir. Jika pernyataan sebelumnya tampak salah, itu karena kode mencoba melakukan terlalu banyak. Jadi, mari kita mundur dan memperbaiki:

 const StyledTextField = styled.input` width: 100%; height: 40px; // 1. Empty state ${(props) => props.empty && css` color: none; backgroundcolor: white; `} // 2. Active state ${(props) => props.active && css` color: black; backgroundcolor: whitesmoke; `} // 3. Filled state ${(props) => props.filled && css` color: black; backgroundcolor: white; border: 1px solid green; `} `;

Penyempurnaan kami membagi gaya menjadi tiga bagian berbeda yang dapat diatur dan mudah dipahami. Ini adalah kemenangan.

Manajer Lembar Gaya

Seperti helper CSS, StyleSheetManager adalah metode helper untuk memodifikasi bagaimana gaya diproses. Dibutuhkan alat peraga tertentu — seperti disableVendorPrefixes (Anda dapat melihat daftar lengkapnya) — yang membantu Anda memilih keluar dari awalan vendor dari subpohonnya.

 import styled, {StyleSheetManager} from "styled-components"; const StyledCard = styled.div` width: 200px; backgroundcolor: white; `; const StyledNav = styled.div` width: calc(100% - var(--side-nav-width)); `; function Profile() { return ( <div> <StyledNav /> <StyleSheetManager disableVendorPrefixes> <StyledCard> This is a card </StyledCard> </StyleSheetManager> </div> ); }

disableVendorPrefixes diteruskan sebagai prop ke <StyleSheetManager> . Jadi, komponen bergaya yang dibungkus oleh <StyleSheetManager> akan dinonaktifkan, tetapi bukan yang ada di <StyledNav> .

Debugging Lebih Mudah

Saat memperkenalkan komponen bergaya ke salah satu rekan saya, salah satu keluhan mereka adalah sulitnya menemukan elemen yang dirender di DOM — atau di React Developer Tools, dalam hal ini. Ini adalah salah satu kelemahan komponen gaya: Dalam mencoba memberikan nama kelas yang unik, ia memberikan hash unik ke elemen, yang kebetulan samar, tetapi membuat displayName dapat dibaca untuk debugging lebih mudah.

 import React from "react"; import styled from "styled-components"; import "./App.css"; const LoginButton = styled.button` background-color: white; color: black; border: 1px solid red; `; function App() { return ( <div className="App"> <LoginButton>Login</LoginButton> </div> ); }

Secara default, komponen bergaya membuat LoginButton sebagai <button class="LoginButton-xxxx xxxx">Login</button> di DOM, dan sebagai LoginButton di React Developer Tools, yang membuat debugging lebih mudah. Kita dapat mengaktifkan boolean displayName jika kita tidak menginginkan perilaku ini. Ini membutuhkan konfigurasi Babel.

Catatan : Dalam dokumentasi, paket babel-plugin-styled-components ditentukan, serta file konfigurasi .babelrc . Masalahnya adalah, karena kami menggunakan create-react-app , kami tidak dapat mengonfigurasi banyak hal kecuali kami mengeluarkannya. Di sinilah makro Babel masuk.

Kita perlu menginstal babel-plugin-macros dengan npm atau Yarn, dan kemudian membuat babel-plugin-macros.config.js di root aplikasi kita, dengan konten:

 module.exports = { styledComponents: { displayName: true, fileName: false, }, };

Dengan nilai fileName terbalik, displayName akan diawali dengan nama file untuk presisi yang lebih unik.

Kami juga sekarang perlu mengimpor dari macro :

 // Before import styled from "styled-components"; // After import styled from "styled-components/macro";

Kesimpulan

Sekarang Anda dapat menyusun CSS Anda secara terprogram, jangan menyalahgunakan kebebasan. Untuk apa nilainya, lakukan yang terbaik untuk menjaga kewarasan dalam komponen gaya Anda. Jangan mencoba untuk membuat persyaratan yang berat, atau menganggap bahwa setiap hal harus menjadi komponen gaya. Juga, jangan terlalu abstrak dengan membuat komponen bergaya baru lahir untuk kasus penggunaan yang hanya Anda duga ada di sekitar sudut.

Sumber Daya Lebih Lanjut

  1. Dokumentasi, Komponen Bergaya
  2. “Membangun Sistem Komponen yang Dapat Digunakan Kembali dengan React.js dan komponen bergaya”, Lukas Gisder-Dube
  3. Penggunaan dengan Next.js
  4. Penggunaan dengan Gatsby