Construirea de componente React reutilizabile folosind Tailwind

Publicat: 2022-03-10
Rezumat rapid ↬ Tailwind este un cadru CSS popular pentru utilitate care oferă dezvoltatorilor web nume de clase de nivel scăzut. Nu are JavaScript și funcționează bine cu cadrele existente, cum ar fi React, Vue, Angular, Ember și altele. Deși acest lucru este pozitiv, poate fi confuz pentru noii dezvoltatori să înțeleagă cum să integreze Tailwind în aplicațiile lor. În acest articol, vom explora modalități de a construi componente React reutilizabile folosind Tailwind.

În această postare, vom analiza mai multe moduri diferite în care puteți construi componente React reutilizabile care folosesc Tailwind sub capotă în timp ce expuneți o interfață plăcută altor componente. Acest lucru vă va îmbunătăți codul, trecând de la liste lungi de nume de clase la elemente semantice care sunt mai ușor de citit și de întreținut.

Va trebui să fi lucrat cu React pentru a înțelege bine această postare.

Tailwind este un cadru CSS foarte popular care oferă clase de utilitate de nivel scăzut pentru a ajuta dezvoltatorii să construiască design-uri personalizate. A crescut în popularitate în ultimii ani, deoarece rezolvă foarte bine două probleme:

  1. Tailwind facilitează efectuarea de modificări iterative la HTML fără a căuta prin foile de stil pentru a găsi selectoare CSS potrivite.
  2. Tailwind are convenții și valori implicite sănătoase. Acest lucru face ca oamenii să înceapă ușor fără a scrie CSS de la zero.

Adăugați documentația cuprinzătoare și nu este surprinzător de ce Tailwind este atât de popular.

Aceste metode vă vor ajuta să transformați codul care arată astfel:

 <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> Enable </button>

Pentru a codifica care arată astfel:

 <Button size="sm" textColor="white" bgColor="blue-500"> Enable </Button>

Diferența dintre ambele fragmente este că în primul am folosit o etichetă standard de buton HTML, în timp ce al doilea a folosit o componentă <Button> . Componenta <Button> a fost construită pentru a fi reutilizată și este mai ușor de citit, deoarece are o semantică mai bună. În loc de o listă lungă de nume de clase, folosește proprietăți pentru a seta diverse atribute, cum ar fi size , textColor și bgColor .

Să începem.

Mai multe după săritură! Continuați să citiți mai jos ↓

Metoda 1: Controlul claselor cu modulul Classnames

O modalitate simplă de a adapta Tailwind într-o aplicație React este să îmbrățișați numele claselor și să le comutați programatic.

Modulul classnames npm facilitează comutarea între clase în React. Pentru a demonstra cum puteți utiliza acest lucru, să luăm un caz de utilizare în care aveți componente <Button> în aplicația dvs. React.

 // This could be hard to read. <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Enable</button> // This is more conventional React. <Button size="sm" textColor="white" bgColor="blue-500">Enable</Button>

Să vedem cum să separăm clasele Tailwind, astfel încât oamenii care folosesc această componentă <Button> să poată folosi elemente de recuzită React, cum ar fi size , textColor și bgColor .

  1. Treceți elemente de recuzită precum bgColor și textColor direct în șablonul șir de nume de clasă.
  2. Utilizați obiecte pentru a schimba în mod programatic numele claselor (cum am făcut cu size prop)

În exemplul de cod de mai jos, vom arunca o privire asupra ambelor abordări.

 // Button.jsx import classnames from 'classnames'; function Button ({size, bgColor, textColor, children}) { return ( <button className={classnames("bg-${bgColor} text-${textColor} font-bold py-2 px-4 rounded", { "text-xs": size === 'sm' "text-xl": size === 'lg', })}> {children} </button> ) }; export default Button;

În codul de mai sus, definim o componentă Button care are următoarele elemente de recuzită:

  • size
    Definește dimensiunea butonului și aplică clasele Tailwind text-xs sau text-xl
  • bgColor
    Definește culoarea de fundal a butonului și aplică clasele Tailwind bg-* .
  • textColor
    Definește culoarea textului butonului și aplică text-* classes .
  • children
    Orice subcomponente vor fi trecute aici. De obicei, va conține textul din <Button> .

Prin definirea Button.jsx , acum îl putem importa și folosi elemente de recuzită React în loc de numele claselor. Acest lucru face codul nostru mai ușor de citit și reutilizat.

 import Button from './Button'; <Button size="sm" textColor="white" bgColor="blue-500">Enable</Button>

Utilizarea numelor de clasă pentru componentele interactive

Un buton este un caz de utilizare foarte simplu. Ce zici de ceva mai complicat? Ei bine, puteți duce acest lucru mai departe pentru a crea componente interactive.

De exemplu, să ne uităm la un meniu derulant care este realizat folosind Tailwind.


Un meniu derulant interactiv creat folosind Tailwind și comutarea numelui clasei.

Pentru acest exemplu, creăm componenta HTML folosind nume de clasă CSS Tailwind, dar expunem o componentă React care arată astfel:

 <Dropdown options={\["Edit", "Duplicate", "Archive", "Move", "Delete"\]} onOptionSelect={(option) => { console.log("Selected Option", option)} } />

Privind codul de mai sus, veți observa că nu avem nicio clasă Tailwind. Toate sunt ascunse în codul de implementare al <Dropdown/> . Utilizatorul acestei componente Dropdown trebuie doar să furnizeze o listă de options și un handler de clic, pe onOptionSelect atunci când se face clic pe o option .

Să vedem cum poate fi construită această componentă folosind Tailwind.

Îndepărtând o parte din codul care nu are legătură, iată cheia logicii. Puteți vizualiza acest Codepen pentru un exemplu complet.

 import classNames from 'classnames'; function Dropdown({ options, onOptionSelect }) { // Keep track of whether the dropdown is open or not. const [isActive, setActive] = useState(false); const buttonClasses = `inline-flex justify-center w-full rounded-md border border-gray-300 px-4 py-2 bg-white text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-blue-500 active:text-gray-200 transition ease-in-out duration-150`; return ( // Toggle the dropdown if the button is clicked <button onClick={() => setActive(!isActive)} className={buttonClasses}> Options </button> // Use the classnames module to toggle the Tailwind .block and .hidden classes <div class={classNames("origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg", { block: isActive, hidden: !isActive })}> // List items are rendered here. {options.map((option) => <div key={option} onClick={(e) => onOptionSelect(option)}>{option}</div>)} </div> ) } export default Dropdown;

Meniul derulant este făcut interactiv prin afișarea sau ascunderea selectivă folosind clasele .hidden și .block . Ori de câte ori <button> este apăsat, declanșăm handlerul onClick care comută starea isActive . Dacă butonul este activ ( isActive === true ), setăm clasa de block . În caz contrar, setăm clasa hidden . Acestea sunt ambele clase Tailwind pentru comutarea comportamentului de afișare.

În rezumat, modulul classnames este o modalitate simplă și eficientă de a controla programatic numele claselor pentru Tailwind. Facilitează separarea logicii în elementele de recuzită React, ceea ce face componentele mai ușor de reutilizat. Funcționează pentru componente simple și interactive.

Metoda 2: Utilizarea constantelor pentru a defini un sistem de proiectare

Un alt mod de a folosi împreună Tailwind și React este prin utilizarea constantelor și maparea elementelor de recuzită la o constantă specifică. Acest lucru este eficient pentru sistemele de proiectare a clădirilor. Să demonstrăm cu un exemplu.

Începeți cu un fișier theme.js în care vă enumerați sistemul de design.

 // theme.js (you can call it whatever you want) export const ButtonType = { primary: "bg-blue-500 hover:bg-blue-700 text-white font-bold rounded", secondary: "bg-blue-500 hover:bg-blue-700 text-white font-bold rounded", basic: "bg-white hover:bg-gray-700 text-gray-700 font-bold rounded", delete: "bg-red-300 hover:bg-red-500 text-white font-bold rounded" }; export const ButtonSize = { sm: "py-2 px-4 text-xs", lg: "py-3 px-6 text-lg" }

În acest caz, avem două seturi de constante:

  • ButtonType definește modul în care butoanele sunt stilate în aplicația noastră.
  • ButtonSizes definește dimensiunile butoanelor din aplicația noastră.

Acum, să scriem componenta noastră <Button> :

 import {ButtonType, ButtonSize} from './theme'; function Button({size, type, children}) { // This can be improved. I'm keeping it simple here by joining two strings. const classNames = ButtonType[type] + " " + ButtonSize[size]; return ( <button className={classNames}>{children}</button> ) } export default Button;

Folosim constantele ButtonType și ButtonSize pentru a crea o listă de nume de clase. Acest lucru face interfața <Button> mult mai plăcută. Ne permite să folosim elemente de recuzită pentru size și type în loc să punem totul într-un șir de nume de clasă.

 // Cleaner and well defined props. <Button size="xs" type="primary">Enable</Button>

Față de abordarea anterioară:

 // Exposing class names <button className="py-2 px-4 text-xs bg-blue-500 hover:bg-blue-700 text-white font-bold rounded">Enable</button>

Dacă trebuie să redefiniți cum arată butoanele în aplicația dvs., trebuie doar să editați fișierul theme.js și toate butoanele din aplicația dvs. se vor actualiza automat. Acest lucru poate fi mai ușor decât căutarea numelor de clasă în diferite componente.

Metoda 3: Compunerea utilităților cu @apply

O a treia modalitate de a îmbunătăți lizibilitatea componentelor dvs. React este utilizarea CSS și a modelului @apply disponibil în PostCSS pentru a extrage clase repetate. Acest model implică utilizarea foilor de stil și post-procesoarelor.

Să demonstrăm cum funcționează acest lucru printr-un exemplu. Să presupunem că aveți un grup de butoane care are un buton primar și un buton secundar.

Un grup de butoane constând dintr-un buton principal și un buton secundar
Un grup de butoane constând dintr-un buton principal și un buton secundar. (Previzualizare mare)
 <button className="py-2 px-4 mr-4 text-xs bg-blue-500 hover:bg-blue-700 text-white font-bold rounded">Update Now</button> <button className="py-2 px-4 text-xs mr-4 hover:bg-gray-100 text-gray-700 border-gray-300 border font-bold rounded">Later</button>

Folosind modelul @apply , puteți scrie acest HTML ca:

 <button className="btn btn-primary btn-xs">Update Now</button> <button className="btn btn-secondary btn-xs">Later</button>

Care poate fi apoi adoptat pentru React pentru a deveni:

 import classnames from "classnames"; function Button ({size, type, children}) { const bSize = "btn-" + size; const bType = "btn-" + type; return ( <button className={classnames("btn", bSize, bType)}>{children}</button> ) } Button.propTypes = { size: PropTypes.oneOf(['xs, xl']), type: PropTypes.oneOf(['primary', 'secondary']) }; // Using the Button component. <Button type="primary" size="xs">Update Now</Button> <Button type="secondary" size="xs">Later</Button>

Iată cum ați crea aceste nume de clasă în stil BEM, cum ar fi .btn , .btn-primary și altele. Începeți prin a crea un fișier button.css :

 /\* button.css \*/ @tailwind base; @tailwind components; .btn { @apply py-2 px-4 mr-4 font-bold rounded; } .btn-primary { @apply bg-blue-500 hover:bg-blue-700 text-white; } .btn-secondary { @apply hover:bg-gray-700 text-gray-700 border-gray-300 border; } .btn-xs { @apply text-xs; } .btn-xl { @apply text-xl; } @tailwind utilities;

Codul de mai sus nu este CSS real , dar va fi compilat de PostCSS. Există un depozit GitHub disponibil aici, care arată cum să configurați PostCSS și Tailwind pentru un proiect JavaScript.

Există, de asemenea, un scurt videoclip care demonstrează cum să-l configurați aici.

Dezavantajele @apply

Conceptul de extragere a claselor de utilitate Tailwind în clase CSS de nivel superior pare să aibă sens, dar are câteva dezavantaje de care ar trebui să fii conștient. Să le evidențiem cu un alt exemplu.

În primul rând, prin extragerea acestor nume de clasă, pierdem unele informații. De exemplu, trebuie să fim conștienți de faptul că .btn-primary trebuie adăugat la o componentă care are deja aplicat .btn . De asemenea, .btn-primary și .btn-secondary nu pot fi aplicate împreună. Această informație nu este evidentă doar privind la clase.

Dacă această componentă ar fi ceva mai complicat, ar trebui să înțelegeți și relația părinte-copil dintre clase. Într-un fel, aceasta este problema pentru care Tailwind a fost proiectat să o rezolve și, folosind @apply , readucem problemele, într-un mod diferit.

Iată un videoclip în care Adam Wathan – creatorul lui Tailwind – se scufundă în avantajele și dezavantajele utilizării @apply .

rezumat

În acest articol, am analizat trei moduri prin care puteți integra Tailwind într-o aplicație React pentru a construi componente reutilizabile. Aceste metode vă ajută să construiți componente React care au o interfață mai curată folosind elemente de props .

  1. Utilizați modulul Classnames pentru a comuta programatic între clase.
  2. Definiți un fișier de constante în care definiți o listă de clase per starea componentei.
  3. Utilizați @apply pentru a extrage clase CSS de nivel superior.

Dacă aveți întrebări, trimiteți-mi un mesaj pe Twitter la @tilomitra.

Lectură recomandată pe SmashingMag:

  • Configurarea CSS Tailwind într-un proiect React
  • Crearea de tabele sortabile cu React
  • Un ghid pentru instrumentele CSS DevTools noi și experimentale în Firefox
  • Creați propriile panouri de conținut pentru extindere și contractare