Tailwind CSS Academy · Pelajaran

Kelas Bersyarat dalam React

Gunakan clsx atau tailwind-merge untuk menggunakan dan menggabungkan kelas Tailwind secara bersyarat berdasarkan props serta keadaan komponen tanpa konflik kelas.

Pelajaran 2 daripada 413 langkah

Kelas Bersyarat dalam React ialah pelajaran Tailwind CSS Academy percuma di CoddyKit. Ini ialah pelajaran 2 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Tailwind CSS Academy, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Tailwind CSS Academy merangkumi sejumlah 4 pelajaran.

Masalah dengan Penggabungan Rentetan

Menggunakan kelas Tailwind secara bersyarat dalam React pada mulanya mudah, tetapi penggabungan rentetan secara naif cepat menimbulkan kesilapan. Menggabungkan rentetan dengan literal templat boleh memasukkan undefined atau false ke dalam className secara tidak sengaja, lalu menghasilkan nama kelas yang tidak sah dalam DOM. Lebih serius lagi, utiliti Tailwind yang bercanggah — seperti text-blue-500 dan text-red-500 — tidak membatalkan satu sama lain; susunan dalam helaian gaya menentukan yang menang, bukannya susunan dalam rentetan className anda.

// 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>
  );
}

Menggunakan clsx untuk Kelas Bersyarat

clsx ialah utiliti kecil yang membina rentetan className dengan selamat daripada syarat, objek dan tatasusunan. Ia menapis nilai palsu seperti false, null dan undefined, supaya DOM anda sentiasa menerima nama kelas yang bersih. Anda boleh menghantar rentetan, objek dengan nilai boolean atau tatasusunan bagi kedua-duanya. Pasangkannya dengan npm install clsx dan import di mana-mana sahaja anda memerlukan logik kelas bersyarat.

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>
  );
}

Sintaks Objek clsx

clsx menerima sintaks objek yang menggunakan kunci sebagai nama kelas dan nilai sebagai syarat boolean. Ini amat mudah dibaca apabila terdapat banyak kelas bersyarat yang dikumpulkan mengikut tujuan. Anda boleh mencampurkan sintaks objek dengan argumen rentetan berposisi dalam panggilan clsx yang sama, supaya kelas asas tanpa syarat mudah dipisahkan daripada kelas varian bersyarat.

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>
  );
}

Masalah Percanggahan Kelas

Walaupun clsx menghasilkan rentetan kelas yang bersih, percanggahan kelas Tailwind masih menjadi masalah. Jika induk menggunakan text-blue-500 dan anak atau penggantian menggunakan text-red-500, kedua-dua kelas muncul dalam DOM. Susunan lata CSS (bukan susunan DOM) menentukan yang menang — iaitu kelas yang dijana Tailwind paling akhir dalam helaian gaya. Hal ini menjadikan tingkah laku penggantian sukar dijangka, terutamanya apabila prop className dihantar oleh pemanggil.

// 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 intent

tailwind-merge Menyelesaikan Percanggahan

tailwind-merge (twMerge) memahami kumpulan utiliti Tailwind dan memastikan nilai terakhir bagi mana-mana sifat yang bercanggah menjadi pemenang. Ia memahami bahawa bg-blue-500 dan bg-red-500 kedua-duanya menetapkan background-color, lalu hanya mengekalkan nilai yang terakhir. Pasangkannya dengan npm install tailwind-merge dan balut panggilan clsx anda dengan twMerge untuk tingkah laku penggantian yang boleh dijangka.

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)

Corak Pembantu cn()

Dalam kebanyakan projek Next.js dan React, anda akan melihat fungsi utiliti bernama cn() yang menggabungkan clsx dan tailwind-merge dalam satu panggilan mudah. Corak ini begitu biasa sehingga create-next-app dengan shadcn/ui menyertakannya secara lalai. Takrifkannya sekali dalam fail utiliti dan import di mana-mana sahaja anda memerlukan pengendalian kelas bersyarat tanpa percanggahan.

// 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>
  );
}

Kelas Bersyarat Berdasarkan Keadaan

Pembantu cn() amat berguna apabila keadaan komponen memacu perubahan visual. Suis togol, item navigasi aktif atau medan borang dengan ralat pengesahan semuanya memerlukan kelas yang berubah berdasarkan keadaan JavaScript. Menggunakan cn dengan sintaks objek menjadikan hubungan antara keadaan dan gaya mudah difahami — sesiapa sahaja yang membaca komponen itu dapat melihat dengan tepat kelas yang digunakan bagi setiap syarat.

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>
  );
}

Menghantar Prop className dengan Selamat

Keputusan reka bentuk utama bagi komponen boleh guna semula ialah cara mengendalikan prop className. Menggunakan twMerge memastikan kelas yang diberikan oleh pemanggil menggantikan lalai dengan betul. Walau bagaimanapun, sesetengah kelas tidak sepatutnya boleh digantikan — seperti kelas struktur yang menentukan susun atur komponen. Salah satu coraknya ialah menggunakan kelas struktur tanpa penggabungan dan hanya menggabungkan kelas persembahan dengan input pemanggil.

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}
    />
  );
}

Mengelakkan Nama Kelas Dinamik

Enjin JIT Tailwind mengesan nama kelas dengan mengimbas fail sumber sebagai rentetan lengkap. Jangan sesekali membina nama kelas secara dinamik dengan menggabungkan rentetan separa seperti 'text-' + color + '-500'. Pengimbas JIT tidak akan mengesannya dan kelas tersebut akan dibuang daripada himpunan pengeluaran. Sentiasa gunakan rentetan nama kelas yang lengkap, walaupun hal itu menyebabkan ungkapan bersyarat menjadi lebih panjang.

// 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])} />

Menyimpan Pengiraan Kelas dalam Memo

Apabila komponen kerap dipaparkan semula dan mempunyai pengiraan className yang kompleks, pertimbangkan untuk menyimpan hasilnya dalam memo dengan useMemo. Operasi clsx dan twMerge adalah pantas, tetapi bagi komponen yang dipaparkan beratus kali sesaat (seperti item senarai maya), penjimatan kecil pun terkumpul. Lebih lazim lagi, mengekstrak pengiraan kelas ke dalam pemboleh ubah di luar JSX meningkatkan kebolehbacaan tanpa mengira prestasi.

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>;
}

Menguji Logik Kelas Bersyarat

Tulis ujian unit untuk komponen dengan logik kelas bersyarat yang kompleks bagi mencegah kemerosotan. Dengan React Testing Library, anda boleh menegaskan bahawa kelas Tailwind tertentu hadir atau tiada berdasarkan nilai prop. Ini amat penting bagi kelas yang berkaitan dengan kebolehcapaian — menguji bahawa butang yang dilumpuhkan mempunyai cursor-not-allowed dan opacity-50 memberikan keyakinan bahawa petunjuk antara muka pengguna adalah betul.

// 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');
});

Semakan Ringkas

Uji pemahaman anda tentang konsep Tailwind CSS Mastery daripada pelajaran ini.

Ulang Kaji Pelajaran

Dalam pelajaran ini, anda telah mempelajari bahawa: clsx membina rentetan kelas bersyarat dengan selamat dengan menapis nilai palsu, tailwind-merge menyelesaikan utiliti Tailwind yang bercanggah supaya nilai yang digunakan terakhir menjadi pemenang, dan pembantu cn() menggabungkan kedua-duanya dalam satu panggilan yang digunakan di seluruh projek React anda. Seterusnya, kita akan meneroka Varian Komponen dengan CVA untuk API varian bertip.

Percuma untuk bermula

Pelajari HTML dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
30
Pelajaran
120

Soalan Lazim

Adakah pelajaran “Kelas Bersyarat dalam React” percuma?

Ya — teks penuh “Kelas Bersyarat dalam React” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus Tailwind CSS Academy, tingkat taraf kepada CoddyKit PRO. Kursus Tailwind CSS Academy merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Kelas Bersyarat dalam React”?

Gunakan clsx atau tailwind-merge untuk menggunakan dan menggabungkan kelas Tailwind secara bersyarat berdasarkan props serta keadaan komponen tanpa konflik kelas. Anda berlatih Tailwind CSS Academy menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan Tailwind CSS Academy?

Tiada pengalaman terdahulu diperlukan. Pembelajaran Tailwind CSS Academy di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 2 daripada 4.

Berapa lamakah pelajaran “Kelas Bersyarat dalam React” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran Tailwind CSS Academy ini?

Ya. Setiap pelajaran Tailwind CSS Academy menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Menyediakan Tailwind dalam Next.js
  2. Kelas Bersyarat dalam React
  3. Varian Komponen dengan CVA
  4. Mengelakkan Konflik Kelas dengan tailwind-merge
← Kembali ke Tailwind CSS Academy