React'te Styled-Components Nasıl Kullanılır
Yayınlanan: 2022-03-10Tarz bileşenleri, bileşenler ve stil arasındaki boşluğu dolduran ve bileşenleri işlevsel ve yeniden kullanılabilir bir şekilde şekillendirmeye başlamanız için çok sayıda özellik sunan bir JS içinde CSS aracıdır. Bu makalede, stilize edilmiş bileşenlerin temellerini ve bunları React uygulamalarınıza nasıl düzgün şekilde uygulayacağınızı öğreneceksiniz. Bu eğitime geçmeden önce React üzerinde çalışmış olmanız gerekirdi. React bileşenlerini şekillendirmede çeşitli seçenekler arıyorsanız, konuyla ilgili önceki yazımıza göz atabilirsiniz.
CSS'nin temelinde, DOM ağacındaki konumu ne olursa olsun herhangi bir HTML öğesini küresel olarak hedefleyebilme yeteneği vardır. Bu, bileşenlerle birlikte kullanıldığında bir engel olabilir, çünkü bileşenler, makul bir ölçüde, kullanıldıkları yere (yerelleştirme olarak bilinir) daha yakın bir yerde birlikte yerleşim (yani, durumlar ve stil gibi varlıkların tutulması) gerektirir.
React'in kendi sözleriyle, stilli bileşenler “bileşenler için görsel ilkellerdir ” ve amaçları bize bileşenleri stilize etmek için esnek bir yol vermektir. Sonuç, bileşenler ve stilleri arasında sıkı bir bağlantıdır.
Not: Tarz bileşenleri hem React hem de React Native için mevcuttur ve React Native rehberine mutlaka göz atmanız gerekirken, buradaki odak noktamız React için stilize edilmiş bileşenler olacaktır.
Neden Tarz Bileşenler?
Stilleri kapsamanıza yardımcı olmanın yanı sıra, stilli bileşenler aşağıdaki özellikleri içerir:
- Otomatik satıcı ön eki
Standart CSS özelliklerini kullanabilirsiniz ve stillendirilmiş bileşenler, gerektiğinde satıcı öneklerini ekler. - Benzersiz sınıf adları
Tarzlanmış bileşenler birbirinden bağımsızdır ve adları hakkında endişelenmenize gerek yoktur çünkü kitaplık bunu sizin için halleder. - Ölü stillerin ortadan kaldırılması
Tarz bileşenleri, kodunuzda bildirilmiş olsalar bile kullanılmayan stilleri kaldırır. - ve daha fazlası.
Kurulum
Tarz bileşenlerini kurmak kolaydır. Bunu bir CDN aracılığıyla veya Yarn gibi bir paket yöneticisi ile yapabilirsiniz…
yarn add styled-components
… veya npm:
npm i styled-components
Demomuz create-react-app kullanıyor.
Başlayan
Belki de stilli bileşenler hakkında farkedeceğiniz ilk şey sözdizimleridir; bu, stile sahip bileşenlerin arkasındaki sihri anlamazsanız göz korkutucu olabilir. Kısaca söylemek gerekirse, stilli bileşenler, bileşenler ve stiller arasındaki boşluğu kapatmak için JavaScript'in şablon değişmezlerini kullanır. Bu nedenle, stilli bir bileşen oluşturduğunuzda, aslında oluşturduğunuz şey stiller içeren bir React bileşenidir. Şuna benziyor:
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>; }
Burada StyledButton
, stil verilmiş bileşendir ve içerdiği stiller ile bir HTML düğmesi olarak işlenecektir. styled
, stili JavaScript'ten gerçek CSS'ye dönüştüren dahili bir yardımcı program yöntemidir.
Ham HTML ve CSS'de şuna sahip olurduk:
button { background-color: black; font-size: 32px; color: white; } <button> Login </button>
Tarz bileşenleri React bileşenleriyse, sahne kullanabilir miyiz? Evet yapabiliriz.
Sahneye Göre Uyarlama
Tarzlandırılmış bileşenler işlevseldir , bu nedenle öğeleri dinamik olarak kolayca biçimlendirebiliriz. Sayfamızda biri siyah diğeri mavi olmak üzere iki tür butonumuz olduğunu varsayalım. Onlar için iki tarz bileşen oluşturmak zorunda değiliz; dekorlarına göre stillerini uyarlayabiliriz.
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> ) }
StyledButton
, props kabul eden bir React bileşeni olduğundan, bg
prop'unun varlığına veya değerine göre farklı bir arka plan rengi atayabiliriz.
Yine de, düğmemize bir type
vermediğimizi fark edeceksiniz. Hadi bunu yapalım:
function Profile() { return ( <> <StyledButton bg="black" type="button"> Button A </StyledButton> <StyledButton bg="blue" type="submit" onClick={() => alert("clicked")}> Button B </StyledButton> </> ); }
Tarz bileşenleri, aldıkları aksesuar türleri arasında ayrım yapabilir. type
bir HTML özelliği olduğunu bilirler, bu nedenle bg
prop'u kendi işlemlerinde kullanırken aslında <button type="button">Button A</button>
oluştururlar. Bir olay işleyiciyi de nasıl eklediğimize dikkat edin?
Özniteliklerden bahsetmişken, genişletilmiş bir sözdizimi, attrs
yapıcısını kullanarak sahne öğelerini yönetmemizi sağlar. Şuna bakın:
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"}; `;
Genişliği ayarlarken üçlüye nasıl ihtiyacımız olmadığına dikkat edin? Bunun nedeni, bunun için width: props.width || "100%",
width: props.width || "100%",
. Ayrıca, yapabildiğimiz için CSS özel özelliklerini kullandık!
Not: Tarz bileşenleri React bileşenleriyse ve sahne öğelerini geçebiliyorsak, durumları da kullanabilir miyiz? Kütüphanenin GitHub hesabında bu konuyu ele alan bir sorun var.
Genişletme Stilleri
Diyelim ki bir açılış sayfası üzerinde çalışıyorsunuz ve her şeyi merkezde tutmak için kapsayıcınızı belirli bir maksimum genişliğe ayarladınız. Bunun için bir StyledContainer
var:
const StyledContainer = styled.section` max-width: 1024px; padding: 0 20px; margin: 0 auto; `;
Ardından, her iki tarafta 20 piksel yerine 10 piksel dolgulu daha küçük bir kaba ihtiyacınız olduğunu keşfedersiniz. İlk düşünceniz başka bir stilli bileşen oluşturmak olabilir ve haklısınız, ancak stilleri kopyaladığınızı anlamanız fazla zaman almaz.
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; `;
Devam etmeden ve yukarıdaki snippet'te olduğu gibi StyledSmallContainer
oluşturmadan önce, stilleri yeniden kullanmanın ve devralmanın yolunu öğrenelim. spread
operatörünün nasıl çalıştığına az çok benziyor:
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> ); }
StyledSmallContainer
, StyledContainer
tüm stilleri alırsınız, ancak dolgu geçersiz kılınır. Normalde StyledSmallContainer
StyledContainer
oluşturur. Ancak bu, taşa oyulduğu veya değiştirilemeyeceği anlamına gelmez.
"as" Polimorfik Prop
polimorfik prop ile as
oluşturulan son elemanı değiştirebilirsiniz. Bir kullanım durumu, stilleri devralmanızdır (son örnekte olduğu gibi). Örneğin, div
için bir section
StyledSmallContainer
tercih ederseniz, as
prop'u, tercih ettiğiniz öğenin değeriyle stil bileşeninize şu şekilde iletebilirsiniz:
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> ); }
Şimdi StyledSmallContainer
bir div
olarak işlenecek. Değeriniz olarak özel bir bileşeniniz bile olabilir:
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> ); }
Bunu hafife almayın.
SCSS-Benzeri Sözdizimi
CSS ön işlemcisi Stylis, stil verilmiş bileşenlerin iç içe yerleştirme gibi SCSS benzeri sözdizimini desteklemesini sağlar:
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> ); }
Animasyon
Tarzlı bileşenler, (yeniden kullanılabilir) animasyon ana keyframes
yardımcısına sahiptir. Buradaki avantaj, ana karelerin stillendirilen bileşenlerden ayrılacak olması ve gerektiğinde dışa aktarılıp yeniden kullanılabilmesidir.
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; `;
Küresel Stil
CSS-in-JS'nin asıl amacı ve buna bağlı olarak, stillendirilmiş bileşenler stillerin kapsamını belirlemek olsa da, stillendirilmiş bileşenlerin global stilinden de yararlanabiliriz. Çoğunlukla kapsamlı stillerle çalıştığımız için bunun değişmez bir fabrika ayarı olduğunu düşünebilirsiniz, ancak yanılıyorsunuz. Bir düşünün: Kapsam belirleme gerçekten nedir? Teknik olarak - küresel stil adına - buna benzer bir şey yapmamız mümkün:
ReactDOM.render( <StyledApp> <App /> </StyledApp>, document.getElementById("root") );
Ancak, tek varoluş nedeni küresel stil olan bir yardımcı işlevimiz var - createGlobalStyle
. Öyleyse neden sorumluluğunu inkar ediyorsun?
createGlobalStyle
için kullanabileceğimiz bir şey, CSS'yi normalleştirmektir:
import {createGlobalStyle} from "styled-components"; const GlobalStyle = createGlobalStyle` /* Your css reset here */ `; // Use your GlobalStyle function App() { return ( <div> <GlobalStyle /> <Routes /> </div> ); }
Not: createGlobalStyle
ile oluşturulan stiller hiçbir alt öğeyi kabul etmez. Belgelerde daha fazla bilgi edinin.
Bu noktada, neden createGlobalStlye
kullanmakla uğraşmamız gerektiğini merak ediyor olabilirsiniz. İşte birkaç neden:
- Onsuz kök oluşturma dışında hiçbir şeyi hedefleyemeyiz (örneğin,
html
,body
, vb.). -
createGlobalStyle
stilleri enjekte eder ancak herhangi bir gerçek öğe oluşturmaz. Son örneğe yakından bakarsanız, oluşturulacak herhangi bir HTML öğesi belirtmediğimizi fark edeceksiniz. Bu harika çünkü elemana gerçekten ihtiyacımız olmayabilir. Sonuçta, küresel stiller ile ilgileniyoruz. Belirli öğeleri değil, büyük ölçüde seçicileri hedefliyoruz. -
createGlobalStyle
kapsamlı değildir ve uygulamamızın herhangi bir yerinde oluşturulabilir ve DOM'da olduğu sürece geçerli olacaktır. Konsepti düşünün, yapıyı değil.
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> ); }
Yapı hakkında düşünürseniz, app-title
GlobalStyle
içinde ayarlandığı gibi stillendirilmemelidir. Ama bu şekilde çalışmıyor. GlobalStyle
nerede oluşturmayı seçerseniz seçin, bileşeniniz oluşturulduğunda enjekte edilecektir.
Dikkatli olun : createGlobalStyles
yalnızca DOM'daysa ve olduğunda oluşturulacaktır.
CSS Yardımcısı
Stilleri aksesuarlara göre nasıl uyarlayacağımızı zaten gördük. Peki ya biraz daha ileri gitmek istersek? CSS yardımcı işlevi bunu başarmaya yardımcı olur. Durumları olan iki metin giriş alanımız olduğunu varsayalım: boş ve etkin, her biri farklı renkte. Bunu yapabiliriz:
const StyledTextField = styled.input` color: ${(props) => (props.isEmpty ? "none" : "black")}; `;
Her şey yolunda. Daha sonra, başka bir doldurulmuş durumu eklememiz gerekirse, stillerimizi değiştirmemiz gerekir:
const StyledTextField = styled.input` color: ${(props) => props.isEmpty ? "none" : props.active ? "purple" : "blue"}; `;
Şimdi üçlü operasyon karmaşıklık içinde büyüyor. Daha sonra metin giriş alanlarımıza başka bir durum eklersek ne olur? Ya da her duruma renk dışında ek stiller vermek istersek? Stilleri üçlü operasyona sıkıştırmayı hayal edebiliyor musunuz? css
yardımcısı işe yarar.
const StyledTextField = styled.input` width: 100%; height: 40px; ${(props) => (props.empty && css` color: none; backgroundcolor: white; `) || (props.active && css` color: black; backgroundcolor: whitesmoke; `)} `;
Yaptığımız şey, daha fazla stile ve daha anlaşılır ve organize bir sözdizimine uyum sağlamak için üçlü sözdizimimizi bir nevi genişletti. Önceki ifade yanlış görünüyorsa, bunun nedeni kodun çok fazla şey yapmaya çalışmasıdır. Öyleyse geri çekilelim ve düzeltelim:
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; `} `;
İyileştirmemiz, stili üç farklı yönetilebilir ve anlaşılması kolay parçaya böler. Bu bir galibiyet.
Stil Sayfası Yöneticisi
CSS yardımcısı gibi, StyleSheetManager
de stillerin nasıl işlendiğini değiştirmek için yardımcı bir yöntemdir. Alt ağacında satıcı öneklerini devre dışı bırakmanıza yardımcı olacak bazı donanımlar ( disableVendorPrefixes
(tüm listeye göz atabilirsiniz) gibi) gerekir.
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
, <StyleSheetManager>
bir destek olarak geçirilir. Bu nedenle, <StyleSheetManager>
tarafından sarılmış stil bileşenleri devre dışı bırakılır, ancak <StyledNav>
içindekiler devre dışı bırakılır.
Daha Kolay Hata Ayıklama
Meslektaşlarımdan birine tarz bileşenleri tanıtırken, şikayetlerinden biri, işlenmiş bir öğeyi DOM'da veya bu konuda React Geliştirici Araçları'nda bulmanın zor olmasıydı. Bu tarz bileşenlerin dezavantajlarından biridir: Benzersiz sınıf adları sağlamaya çalışırken, öğelere şifreli olan benzersiz karmalar atar, ancak daha kolay hata ayıklama için displayName
okunabilir hale getirir.
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> ); }
Stile sahip bileşenler varsayılan olarak LoginButton
<button class="LoginButton-xxxx xxxx">Login</button>
ve React Developer LoginButton
olarak işler, bu da hata ayıklamayı kolaylaştırır. Bu davranışı istemiyorsak, displayName
değiştirebiliriz. Bunun için bir Babel yapılandırması gerekir.
Not : Belgelerde, babel-plugin-styled-components
paketinin yanı sıra bir .babelrc
yapılandırma dosyası belirtilir. Bununla ilgili sorun şu ki, create-react-app
kullandığımız için, çıkarmadıkça pek çok şeyi yapılandıramayız. Babel makrolarının devreye girdiği yer burasıdır.
babel-plugin-macros
npm veya Yarn ile kurmamız ve ardından uygulamamızın kökünde şu içeriğe sahip bir babel-plugin-macros.config.js
oluşturmamız gerekecek:
module.exports = { styledComponents: { displayName: true, fileName: false, }, };
fileName
değeri ters çevrildiğinde, daha da benzersiz bir kesinlik için displayName
dosya adının önüne eklenir.
Ayrıca şimdi macro
içe aktarmamız gerekiyor:
// Before import styled from "styled-components"; // After import styled from "styled-components/macro";
Çözüm
Artık CSS'nizi programlı olarak oluşturabildiğinize göre, özgürlüğü kötüye kullanmayın. Değeri ne olursa olsun, tarz bileşenlerinizde akıl sağlığını korumak için elinizden gelenin en iyisini yapın. Ağır koşul cümleleri oluşturmaya çalışmayın ve her şeyin stilize edilmiş bir bileşen olması gerektiğini düşünmeyin. Ayrıca, köşede bir yerde olduğunu tahmin ettiğiniz kullanım durumları için yeni ortaya çıkan tarzda bileşenler oluşturarak aşırı soyutlamayın.
Diğer Kaynaklar
- Belgeler, Tarz Bileşenler
- Lukas Gisder-Dube, "React.js ve tarz bileşenlerle Yeniden Kullanılabilir Bir Bileşen Sistemi Oluşturma"
- Next.js ile kullanım
- Gatsby ile Kullanım