React'te Styled-Components Nasıl Kullanılır

Yayınlanan: 2022-03-10
Kısa özet ↬ Bileşen güdümlü yaklaşım, web uygulamaları oluşturma şeklimizde yeni bir çığır açsa da, kusurları da vardır - bunlardan biri CSS ile kullanılabilirliği ve ölçeklenebilirliğidir. Bu, stillerimizi bileşene özel bir şekilde oluşturmanın ve yönetmenin yeni bir yolunu doğurdu, aksi takdirde CSS-in-JS olarak da bilinir.

Tarz 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.

Atlamadan sonra daha fazlası! Aşağıdan okumaya devam edin ↓

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

  1. Belgeler, Tarz Bileşenler
  2. Lukas Gisder-Dube, "React.js ve tarz bileşenlerle Yeniden Kullanılabilir Bir Bileşen Sistemi Oluşturma"
  3. Next.js ile kullanım
  4. Gatsby ile Kullanım