clsx va classnames — dinamik class boshqarish
Muammodan boshlaylik
React da komponentga bir nechta shartli klass qo'shish kerak bo'lsa, ko'pchilik shunday yozadi:
<div className={
'card' +
(isActive ? ' card--active' : '') +
(isDisabled ? ' card--disabled' : '') +
(size === 'lg' ? ' card--large' : '') +
(hasError ? ' card--error' : '')
}>
Yoki template literal bilan:
<div className={`card ${isActive ? 'card--active' : ''} ${isDisabled ? 'card--disabled' : ''} ${hasError ? 'card--error' : ''}`}>
Ikkalasi ham ishlaydi. Lekin o'qish qiyin, xato qilish oson — shart bajarilmasa bo'sh string qoladi va className da ortiqcha bo'shliq hosil bo'ladi: "card card--active".
classnames va clsx bu muammoni hal qiladi.
classnames va clsx — farqi nima?
Ikkalasi bir xil vazifani bajaradi. Farq faqat hajmda:
classnames → ~1.1KB (asl kutubxona, 2013 yildan beri)
clsx → ~0.3KB (classnames ning engillashtirilgan versiyasi)
clsx — classnames ning to'liq o'rnini bosadi, lekin 4 marta kichik. Zamonaviy loyihalarda clsx ishlatiladi. classnames eski loyihalarda ko'rasiz — API bir xil.
npm install clsx
# yoki
npm install classnames
clsx — barcha sintaksis shakllari
String lar
import clsx from 'clsx';
clsx('foo', 'bar') // → "foo bar"
clsx('foo', '', 'bar') // → "foo bar" (bo'sh string o'tkazilmaydi)
clsx('foo', null, 'bar') // → "foo bar" (null o'tkazilmaydi)
clsx('foo', undefined) // → "foo" (undefined o'tkazilmaydi)
clsx('foo', false) // → "foo" (false o'tkazilmaydi)
false, null, undefined, 0, '' — bularning barchasi e'tiborga olinmaydi. Shart bajarilmasa bo'sh joy qolmaydi.
Ob'ekt — shartli klasslar uchun
clsx({ foo: true, bar: false }) // → "foo"
clsx({ foo: true, bar: true }) // → "foo bar"
// O'zgaruvchilar bilan
clsx({
'card--active': isActive,
'card--disabled': isDisabled,
'card--error': hasError,
})
Ob'ektda kalit — klass nomi, qiymat — shart. Qiymat true bo'lsa klass qo'shiladi, false bo'lsa qo'shilmaydi.
Massiv — guruhlash uchun
clsx(['foo', 'bar']) // → "foo bar"
clsx(['foo', null, 'bar']) // → "foo bar"
clsx(['foo', ['bar', 'baz']]) // → "foo bar baz" (ichma-ich massiv)
Aralash — haqiqiy loyihalarda
clsx(
'btn', // har doim
{ 'btn--active': isActive }, // shartli
size && `btn--${size}`, // shartli string
className // tashqaridan
)
React da ishlatish
Asosiy — CSS Modules bilan
import clsx from 'clsx';
import styles from './Button.module.css';
function Button({ variant, size, disabled, fullWidth, className, children }) {
return (
<button
disabled={disabled}
className={clsx(
styles.btn,
styles[variant],
styles[size],
{
[styles.disabled]: disabled,
[styles.fullWidth]: fullWidth,
},
className
)}
>
{children}
</button>
);
}
[styles.disabled] — computed property: klass nomi o'zgaruvchidan olinadi.
Tailwind bilan
import clsx from 'clsx';
function Alert({ type = 'info', children }) {
return (
<div
className={clsx(
'flex items-start gap-3 p-4 rounded-lg border text-sm',
{
'bg-blue-50 border-blue-200 text-blue-800': type === 'info',
'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',
}
)}
>
{children}
</div>
);
}
// Ishlatish
<Alert type="error">Xato yuz berdi</Alert>
<Alert type="success">Muvaffaqiyatli saqlandi</Alert>
cn yordamchi funksiya — Tailwind + clsx + twMerge
Oldingi darsda ko'rgan edik: Tailwind bilan clsx yetarli emas — ziddiyatli klasslar muammosi bor. Shuning uchun tailwind-merge bilan birga ishlatiladi:
// src/lib/utils.js
import clsx from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs) {
return twMerge(clsx(inputs));
}
import { cn } from '@/lib/utils';
function Input({ error, className, ...props }) {
return (
<input
className={cn(
'w-full px-3 py-2 border rounded-md text-sm outline-none',
'focus:ring-2 focus:ring-blue-300 focus:border-blue-500',
error ? 'border-red-400 focus:ring-red-200' : 'border-gray-300',
className // tashqaridan px-5 kelsa — px-3 ni almashtiradi
)}
{...props}
/>
);
}
clsx faqat ishlatiladi degan gapni emas, cn funksiyasi orqali Tailwind ziddiyatlarini ham hal qiladi. Bugungi kunda cn React ekotizimida standartga aylangan — Shadcn/ui, Radix primitives, NextUI kabi kutubxonalarning barchasi shu yondashuvni ishlatadi.
Tez-tez uchraydigan xatolar
String interpolatsiyasini clsx o'rniga ishlatish
// ❌ — shart bajarilmasa "card undefined" bo'ladi
<div className={`card ${isActive && 'card--active'}`}>
// ✅ — clsx false va undefined ni o'tkazmaydi
<div className={clsx('card', isActive && 'card--active')}>
Ob'ektda defisli klass nomi tirnoqsiz
// ❌ SyntaxError — defis JavaScript da kalit sifatida to'g'ridan-to'g'ri yozilmaydi
clsx({ card--active: true })
// ✅ Tirnoqda yoziladi
clsx({ 'card--active': true })
Import unutilishi
// ❌ clsx import qilinmagan — ReferenceError
className={clsx('btn', { active: isActive })}
// ✅
import clsx from 'clsx';
Xulosa
clsx — shartli CSS klasslarni qulay birlashtirish uchun minimal yordamchi. false, null, undefined ni avtomatik o'tkazib yuboradi — className da ortiqcha bo'shliq qolmaydi.
Eslab qoling:
clsx—classnamesning engil versiyasi, ikkalasi API jihatdan bir xil- String, ob'ekt, massiv — uchala sintaksisni aralashtirib ishlatish mumkin
- Ob'ektda:
{ 'klass-nomi': shart }— eng ko'p ishlatiladigan pattern - Tailwind bilan —
cn = twMerge(clsx(...))funksiyasi standart yondashuv - Defisli klass nomlar ob'ektda tirnoqda yoziladi
Foydali havolalar
- npmjs.com/package/clsx — clsx sahifasi
- npmjs.com/package/classnames — classnames sahifasi
Keyingi dars
39-dars: React Router nima, o'rnatish, asosiy tushunchalar