Costruire componenti React riutilizzabili utilizzando Tailwind
Pubblicato: 2022-03-10In questo post, esamineremo diversi modi in cui puoi costruire componenti React riutilizzabili che sfruttano Tailwind sotto il cofano mentre espongono una bella interfaccia ad altri componenti. Ciò migliorerà il tuo codice passando da lunghi elenchi di nomi di classi a prop semantici più facili da leggere e mantenere.
Dovrai aver lavorato con React per ottenere una buona comprensione di questo post.
Tailwind è un framework CSS molto popolare che fornisce classi di utilità di basso livello per aiutare gli sviluppatori a creare progetti personalizzati. È diventato popolare negli ultimi anni perché risolve molto bene due problemi:
- Tailwind rende facile apportare modifiche iterative all'HTML senza scavare nei fogli di stile per trovare i selettori CSS corrispondenti.
- Tailwind ha convenzioni e impostazioni predefinite sane. Questo rende facile per le persone iniziare senza scrivere CSS da zero.
Aggiungi la documentazione completa e non sorprende il motivo per cui Tailwind è così popolare.
Questi metodi ti aiuteranno a trasformare il codice che assomiglia a questo:
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> Enable </button>
Per codificare in questo modo:
<Button size="sm" textColor="white" bgColor="blue-500"> Enable </Button>
La differenza tra entrambi gli snippet è che nel primo abbiamo utilizzato un tag di pulsante HTML standard, mentre il secondo utilizzava un componente <Button>
. Il componente <Button>
è stato creato per essere riutilizzabile ed è più facile da leggere poiché ha una semantica migliore. Invece di un lungo elenco di nomi di classi, usa le proprietà per impostare vari attributi come size
, textColor
e bgColor
.
Iniziamo.
Metodo 1: controllo delle classi con il modulo Classnames
Un modo semplice per adattare Tailwind in un'applicazione React consiste nell'abbracciare i nomi delle classi e attivarli a livello di codice.
Il modulo classnames npm rende facile alternare le classi in React. Per dimostrare come puoi usarlo, prendiamo un caso d'uso in cui hai componenti <Button>
nella tua applicazione 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>
Vediamo come separare le classi Tailwind in modo che le persone che usano questo componente <Button>
possano usare oggetti di scena React come size
, textColor
e bgColor
.
- Passa oggetti di scena come
bgColor
etextColor
direttamente nel modello di stringa del nome della classe. - Usa gli oggetti per cambiare a livello di codice i nomi delle classi (come abbiamo fatto con il
size
prop)
Nel codice di esempio seguente, daremo un'occhiata a entrambi gli approcci.
// 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;
Nel codice sopra, definiamo un componente Button
che accetta i seguenti prop:
-
size
Definisce la dimensione del pulsante e applica le classi Tailwindtext-xs
otext-xl
-
bgColor
Definisce il colore di sfondo del pulsante e applica le classi Tailwindbg-*
. -
textColor
Definisce il colore del testo del pulsante e applica letext-* classes
. -
children
Eventuali sottocomponenti verranno passati qui. Di solito conterrà il testo all'interno del<Button>
.
Definendo Button.jsx
, ora possiamo importarlo e utilizzare gli oggetti di scena React invece dei nomi delle classi. Questo rende il nostro codice più facile da leggere e riutilizzare.
import Button from './Button'; <Button size="sm" textColor="white" bgColor="blue-500">Enable</Button>
Utilizzo dei nomi delle classi per i componenti interattivi
Un pulsante è un caso d'uso molto semplice. Che ne dici di qualcosa di più complicato? Bene, puoi andare oltre per creare componenti interattivi.
Ad esempio, diamo un'occhiata a un menu a discesa creato utilizzando Tailwind.
Un menu a discesa interattivo creato utilizzando Tailwind e la commutazione del nome della classe.
Per questo esempio, creiamo il componente HTML usando i nomi di classe CSS di Tailwind ma esponiamo un componente React che assomiglia a questo:
<Dropdown options={\["Edit", "Duplicate", "Archive", "Move", "Delete"\]} onOptionSelect={(option) => { console.log("Selected Option", option)} } />
Osservando il codice sopra, noterai che non abbiamo classi Tailwind. Sono tutti nascosti all'interno del codice di implementazione di <Dropdown/>
. L'utente di questo componente a Dropdown
deve solo fornire un elenco di options
e un gestore di clic, onOptionSelect
quando si fa clic su option
.
Vediamo come creare questo componente utilizzando Tailwind.
Rimuovendo parte del codice non correlato, ecco il punto cruciale della logica. È possibile visualizzare questo Codepen per un esempio completo.
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;
Il menu a discesa è reso interattivo mostrando o nascondendolo selettivamente utilizzando le classi .hidden
e .block
. Ogni volta che viene premuto il <button>
, viene attivato il gestore onClick
che commuta lo stato isActive
. Se il pulsante è attivo ( isActive === true
), impostiamo la classe di block
. Altrimenti, impostiamo la classe hidden
. Queste sono entrambe classi Tailwind per attivare/disattivare il comportamento di visualizzazione.
In sintesi, il modulo classnames è un modo semplice ed efficace per controllare a livello di codice i nomi delle classi per Tailwind. Semplifica la separazione della logica negli oggetti di scena React, il che rende i tuoi componenti più facili da riutilizzare. Funziona per componenti semplici e interattivi.
Metodo 2: utilizzo delle costanti per definire un sistema di progettazione
Un altro modo per usare Tailwind e React insieme consiste nell'usare costanti e mappare gli oggetti di scena su una costante specifica. Questo è efficace per i sistemi di progettazione degli edifici. Dimostriamo con un esempio.
Inizia con un file theme.js
in cui elenchi il tuo sistema di progettazione.
// 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" }
In questo caso abbiamo due insiemi di costanti:
-
ButtonType
definisce lo stile dei pulsanti nella nostra app. -
ButtonSizes
definisce le dimensioni dei pulsanti nella nostra app.
Ora scriviamo il nostro componente <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;
Usiamo le ButtonType
e ButtonSize
per creare un elenco di nomi di classi. Questo rende l'interfaccia del nostro <Button>
molto più gradevole. Ci consente di utilizzare le size
e il type
di oggetti di scena invece di inserire tutto in una stringa del nome di una classe.
// Cleaner and well defined props. <Button size="xs" type="primary">Enable</Button>
Rispetto all'approccio precedente:
// 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>
Se devi ridefinire l'aspetto dei pulsanti nella tua applicazione, modifica il file theme.js
e tutti i pulsanti nella tua app si aggiorneranno automaticamente. Questo può essere più semplice che cercare i nomi delle classi in vari componenti.
Metodo 3: composizione di utilità con @apply
Un terzo modo per migliorare la leggibilità dei componenti React è utilizzare CSS e il pattern @apply
disponibile in PostCSS per estrarre classi ripetute. Questo modello prevede l'utilizzo di fogli di stile e post-processori.
Dimostriamo come funziona attraverso un esempio. Supponiamo di avere un gruppo di pulsanti che ha un pulsante primario e un pulsante secondario.
<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>
Usando il modello @apply
, puoi scrivere questo HTML come:
<button className="btn btn-primary btn-xs">Update Now</button> <button className="btn btn-secondary btn-xs">Later</button>
Che può poi essere adottato da React per diventare:
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>
Ecco come creare questi nomi di classe in stile BEM come .btn
, .btn-primary
e altri. Inizia creando un file 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;
Il codice sopra non è un vero CSS ma verrà compilato da PostCSS. C'è un repository GitHub disponibile qui che mostra come configurare PostCSS e Tailwind per un progetto JavaScript.
C'è anche un breve video che mostra come configurarlo qui.
Svantaggi dell'utilizzo di @apply
Il concetto di estrarre le classi di utilità Tailwind in classi CSS di livello superiore sembra avere senso, ma presenta alcuni svantaggi di cui dovresti essere consapevole. Evidenziamoli con un altro esempio.
Innanzitutto, estraendo questi nomi di classi, perdiamo alcune informazioni. Ad esempio, dobbiamo essere consapevoli del fatto che .btn-primary
deve essere aggiunto a un componente a cui è già applicato .btn
. Inoltre, .btn-primary
e .btn-secondary
non possono essere applicati insieme. Questa informazione non è evidente solo guardando le classi.
Se questo componente fosse qualcosa di più complicato, dovresti anche capire la relazione genitore-figlio tra le classi. In un certo senso, questo è il problema per cui Tailwind è stato progettato e, utilizzando @apply
, riportiamo i problemi indietro, in un modo diverso.
Ecco un video in cui Adam Wathan, il creatore di Tailwind, si tuffa nei pro e contro dell'utilizzo di @apply
.
Sommario
In questo articolo, abbiamo esaminato tre modi per integrare Tailwind in un'applicazione React per creare componenti riutilizzabili. Questi metodi ti aiutano a costruire componenti React che hanno un'interfaccia più pulita usando props
.
- Utilizzare il modulo nomi di classe per alternare le classi a livello di codice.
- Definisci un file di costanti in cui definisci un elenco di classi per stato del componente.
- Usa
@apply
per estrarre classi CSS di livello superiore.
Se hai domande, mandami un messaggio su Twitter a @tilomitra.
Letture consigliate su SmashingMag:
- Configurazione di Tailwind CSS in un progetto React
- Creazione di tabelle ordinabili con React
- Una guida ai nuovi e sperimentali CSS DevTools in Firefox
- Crea i tuoi pannelli di contenuto in espansione e in contrazione