Ehdolliset luokat Reactissa
Käyttäkää clsx:ää tai tailwind-mergeä Tailwind-luokkien ehdolliseen käyttöönottoon ja turvalliseen yhdistämiseen komponenttien propsien ja tilan perusteella ilman luokkaristiriitoja.
Ehdolliset luokat Reactissa on ilmainen Tailwind CSS Academy-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Tailwind CSS Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Tailwind CSS Academy-kurssilla on yhteensä 4 oppituntia.
Merkkijonojen yhdistämisen ongelma
Tailwind-luokkien käyttäminen ehdollisesti Reactissa on aluksi suoraviivaista, mutta naiivi merkkijonojen yhdistäminen johtaa nopeasti virheisiin. Merkkijonojen yhdistäminen mallimerkkijonoilla voi vahingossa lisätä undefined- tai false-arvon className-määritykseen, mikä johtaa virheellisiin luokkien nimiin DOMissa. Vielä vakavampi ongelma on, etteivät ristiriitaiset Tailwind-apuohjelmat — kuten text-blue-500 ja text-red-500 — kumoa toisiaan. Voittajan ratkaisee tyylitiedoston järjestys, ei className-merkkijonon järjestys.
// Problematic — may include 'false' or 'undefined' in class list
function Button({ disabled, primary }) {
return (
<button
className={'px-4 py-2 rounded ' +
primary && 'bg-blue-500 text-white' + // bug: && short-circuit
disabled && 'opacity-50' // 'false' in string
}
>
Click me
</button>
);
}clsx:n käyttäminen ehdollisiin luokkiin
clsx on pieni apuohjelma, joka muodostaa className-merkkijonoja turvallisesti ehtojen, olioiden ja taulukoiden perusteella. Se suodattaa pois epätotuusarvot, kuten false-, null- ja undefined-arvot, joten DOMiin päätyvät aina siistit luokkien nimet. Voitte välittää sille merkkijonoja, boolean-arvoja sisältäviä olioita tai näiden taulukoita. Asentakaa se komennolla npm install clsx ja tuokaa se käyttöön kaikkialla, missä tarvitsette ehdollista luokkalogiikkaa.
import clsx from 'clsx';
function Button({ disabled, primary, className }) {
return (
<button
className={clsx(
'px-4 py-2 rounded font-medium transition-colors',
primary && 'bg-blue-600 text-white hover:bg-blue-700',
!primary && 'bg-gray-100 text-gray-900 hover:bg-gray-200',
disabled && 'opacity-50 cursor-not-allowed',
className // allow caller to pass extra classes
)}
disabled={disabled}
>
Click me
</button>
);
}clsx-oliosyntaksi
clsx hyväksyy oliosyntaksin, jossa avaimet ovat luokkien nimiä ja arvot boolean-ehtoja. Tämä on erityisen selkeää, kun useita ehdollisia luokkia ryhmitellään tarkoituksen mukaan. Voitte yhdistää olio- ja merkkijonoargumentteja samassa clsx-kutsussa, jolloin ehdottomat perusluokat on helppo erottaa ehdollisista varianttiluokista.
import clsx from 'clsx';
function Alert({ type }) {
return (
<div
className={clsx(
// Unconditional base classes
'rounded-lg border p-4 flex items-start gap-3',
// Conditional classes via object syntax
{
'bg-red-50 border-red-200 text-red-800': type === 'error',
'bg-yellow-50 border-yellow-200 text-yellow-800': type === 'warning',
'bg-green-50 border-green-200 text-green-800': type === 'success',
'bg-blue-50 border-blue-200 text-blue-800': type === 'info'
}
)}
>
{/* alert content */}
</div>
);
}Luokkien välinen ristiriita
Vaikka clsx tuottaa siistejä luokkien merkkijonoja, Tailwind-luokkien ristiriidat ovat edelleen ongelma. Jos isäelementti käyttää luokkaa text-blue-500 ja lapsielementti tai ylikirjoitus luokkaa text-red-500, molemmat luokat näkyvät DOMissa. CSS:n kaskadijärjestys (ei DOM-järjestys) ratkaisee voittajan — voittaja on se, jonka Tailwind on muodostanut tyylitiedostoon viimeisenä. Tämä tekee ylikirjoitusten toiminnasta arvaamatonta etenkin silloin, kun kutsuja välittää className-proppeja.
// Class conflict example
function Badge({ className }) {
return (
<span className={clsx('bg-blue-500 text-white px-2 py-0.5 rounded', className)}>
Tag
</span>
);
}
// Caller tries to override background
<Badge className="bg-red-500" />
// Result: both bg-blue-500 AND bg-red-500 in the DOM
// Which one wins depends on Tailwind's stylesheet order, not your intenttailwind-merge ratkaisee ristiriidat
tailwind-merge (twMerge) tuntee Tailwindin apuohjelmaryhmät ja varmistaa, että kunkin ristiriitaisen ominaisuuden viimeinen arvo voittaa. Se ymmärtää, että bg-blue-500 ja bg-red-500 määrittävät molemmat ominaisuuden background-color, joten se säilyttää niistä vain viimeisen. Asentakaa se komennolla npm install tailwind-merge ja käärikää clsx-kutsunne twMerge-funktion sisään, jotta ylikirjoitukset toimivat ennakoitavasti.
import { twMerge } from 'tailwind-merge';
import clsx from 'clsx';
function Badge({ className }) {
return (
<span
className={twMerge('bg-blue-500 text-white px-2 py-0.5 rounded', className)}
>
Tag
</span>
);
}
// Caller override now works correctly!
<Badge className="bg-red-500" />
// Result: only bg-red-500 (bg-blue-500 is removed by twMerge)cn()-apuohjelmamalli
Useimmissa Next.js- ja React-projekteissa näette cn()-nimisen apufunktion, joka yhdistää clsx:n ja tailwind-merge:n yhdeksi käteväksi kutsuksi. Tämä malli on niin yleinen, että shadcn/ui:n create-next-app sisältää sen oletusarvoisesti. Määritelkää se kerran apuohjelmatiedostossa ja tuokaa se käyttöön kaikkialla, missä tarvitsette ehdollisten ja ristiriidattomien luokkien käsittelyä.
// lib/utils.ts
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
// Usage in any component
import { cn } from '@/lib/utils';
function Card({ className, children }) {
return (
<div className={cn(
'rounded-xl border bg-white shadow-sm p-6',
className
)}>
{children}
</div>
);
}Tilaan perustuvat ehdolliset luokat
cn()-apuohjelma on hyödyllinen erityisesti silloin, kun komponentin tila ohjaa visuaalisia muutoksia. Vaihtokytkin, aktiivinen navigointikohde tai kelpoisuusvirheen sisältävä lomakekenttä tarvitsee luokkia, jotka muuttuvat JavaScript-tilan perusteella. cn-funktion käyttäminen olio-syntaksilla tekee tilan ja tyylien välisestä suhteesta heti selkeän — komponentin lukija näkee suoraan, mitkä luokat otetaan käyttöön missäkin tilanteessa.
import { cn } from '@/lib/utils';
function NavItem({ href, active, children }) {
return (
<a
href={href}
className={cn(
'flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium',
'transition-colors duration-150',
{
'bg-blue-50 text-blue-700': active,
'text-gray-600 hover:bg-gray-100 hover:text-gray-900': !active
}
)}
>
{children}
</a>
);
}className-proppien turvallinen välittäminen
Uudelleenkäytettävien komponenttien keskeinen suunnittelupäätös on className-propin käsittelytapa. twMerge-funktion avulla kutsujan välittämät luokat voivat ylikirjoittaa oletukset asianmukaisesti. Joitakin luokkia ei kuitenkaan pitäisi voida ylikirjoittaa koskaan — esimerkiksi komponentin asettelun määrittäviä rakenteellisia luokkia. Yksi tapa on lisätä rakenteelliset luokat ilman yhdistämistä ja yhdistää kutsujan syötteen kanssa vain esitystapaan liittyvät luokat.
import { cn } from '@/lib/utils';
function Input({ className, hasError, ...props }) {
return (
<input
className={cn(
// Base structural: never overridden
'block w-full rounded-lg border px-3 py-2 text-sm',
'placeholder:text-gray-400 focus:outline-none focus:ring-2',
// Conditional state classes
hasError
? 'border-red-300 focus:ring-red-500'
: 'border-gray-300 focus:ring-blue-500',
// Caller overrides presentational classes
className
)}
{...props}
/>
);
}Dynaamisten luokkien nimien välttäminen
Tailwindin JIT-moottori tunnistaa luokkien nimet etsimällä lähdetiedostoista kokonaisia merkkijonoja. Älkää koskaan muodostako luokkien nimiä dynaamisesti yhdistämällä osittaisia merkkijonoja, kuten 'text-' + color + '-500'. JIT-skanneri ei tunnista näitä, ja luokat poistetaan tuotantopaketista. Käyttäkää aina kokonaisia luokkien nimien merkkijonoja, vaikka tämä tarkoittaisi pidempää ehtolauseketta.
// WRONG — JIT cannot detect these dynamic class names
const colors = { info: 'blue', error: 'red' };
<div className={'text-' + colors[type] + '-500'} />
// CORRECT — full class names that JIT can detect
const colorMap = {
info: 'text-blue-500 bg-blue-50',
error: 'text-red-500 bg-red-50',
success: 'text-green-500 bg-green-50'
};
<div className={cn('rounded p-3', colorMap[type])} />Luokkalaskennan memoizointi
Kun komponentti renderöityy usein ja sen className-laskenta on monimutkaista, harkitkaa tuloksen memoisointia useMemo-hookilla. clsx- ja twMerge-operaatiot ovat nopeita, mutta satoja kertoja sekunnissa renderöityvissä komponenteissa, kuten virtuaalisen listan kohteissa, pienetkin säästöt kertyvät. Yleisemmin luokkalaskennan siirtäminen JSX:n ulkopuoliseen muuttujaan parantaa luettavuutta suorituskyvystä riippumatta.
import { useMemo } from 'react';
import { cn } from '@/lib/utils';
function ListItem({ selected, variant, className }) {
const itemClasses = useMemo(() => cn(
'flex items-center gap-3 px-4 py-3 cursor-pointer',
'border-b border-gray-100 transition-colors',
{
'bg-blue-50 border-l-2 border-l-blue-500': selected,
'hover:bg-gray-50': !selected,
'opacity-50 pointer-events-none': variant === 'disabled'
},
className
), [selected, variant, className]);
return <div className={itemClasses}>{/* content */}</div>;
}Ehdollisen luokkalogiikan testaaminen
Kirjoittakaa yksikkötestit komponenteille, joissa on monimutkaista ehdollista luokkalogiikkaa, jotta regressiot voidaan estää. React Testing Libraryn avulla voitte tarkistaa, ovatko tietyt Tailwind-luokat käytössä prop-arvojen perusteella. Tämä on erityisen tärkeää saavutettavuuden kannalta olennaisille luokille — sen testaaminen, että käytöstä poistetulla painikkeella on cursor-not-allowed- ja opacity-50-luokat, antaa varmuuden käyttöliittymän vihjeiden oikeellisuudesta.
// Button.test.tsx
import { render, screen } from '@testing-library/react';
import { Button } from './Button';
test('disabled button has correct classes', () => {
const { container } = render(
<Button disabled>Submit</Button>
);
const btn = container.firstChild;
expect(btn.className).toContain('opacity-50');
expect(btn.className).toContain('cursor-not-allowed');
});
test('primary variant applies correct colors', () => {
const { container } = render(
<Button primary>Submit</Button>
);
expect(container.firstChild.className).toContain('bg-blue-600');
});Pikatarkistus
Testatkaa tämän oppitunnin Tailwind CSS Mastery -aiheiden ymmärtämistänne.
Oppitunnin yhteenveto
Tässä oppitunnissa opitte, että clsx muodostaa ehdolliset luokkien merkkijonot turvallisesti suodattamalla epätotuusarvot, tailwind-merge ratkaisee ristiriitaiset Tailwind-apuohjelmat niin, että viimeisenä käytetty voittaa, ja cn()-apuohjelma yhdistää nämä molemmat yhdeksi kutsuksi, jota käytetään kaikkialla React-projektissanne. Seuraavaksi tutustumme komponenttivariantteihin ja CVA:n tyypitettyihin variantti-rajapintoihin.
Opi HTML tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 30
- Oppitunnit
- 120
Usein kysytyt kysymykset
Onko oppitunti ”Ehdolliset luokat Reactissa” ilmainen?
Kyllä – oppitunnin ”Ehdolliset luokat Reactissa” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Tailwind CSS Academy-kurssin, päivitä CoddyKit PROhon. Tailwind CSS Academy-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Ehdolliset luokat Reactissa”?
Käyttäkää clsx:ää tai tailwind-mergeä Tailwind-luokkien ehdolliseen käyttöönottoon ja turvalliseen yhdistämiseen komponenttien propsien ja tilan perusteella ilman luokkaristiriitoja. Harjoittelet Tailwind CSS Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni Tailwind CSS Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin Tailwind CSS Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.
Kuinka kauan ”Ehdolliset luokat Reactissa”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä Tailwind CSS Academy-oppitunnilla?
Kyllä. Jokainen Tailwind CSS Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Tailwindin käyttöönotto Next.js:ssä
- Ehdolliset luokat Reactissa
- Komponenttivariantit CVA:lla
- Luokkaristiriitojen välttäminen tailwind-merge-kirjastolla