FluentStack

Compound Components

Mode tersedia: dark, light, paper
MasukDaftar
Advanced · Level 9: React AdvancedAdvanced70 menitBahasa Indonesia

Compound Components

Menyusun component terkait yang berbagi state melalui parent pattern agar API UI tetap mudah dibaca di tempat pemakaian.

StatusMemuat progres
ProgresMemuat...

...

Memuat progres

Menyiapkan langkah berikutnya

Tujuan belajar

  • Menjelaskan kapan beberapa component layak membentuk satu compound pattern
  • Membaca hubungan parent, trigger, dan panel yang berbagi state
  • Membangun tabs kecil dengan API yang tetap terlihat jelas di JSX
ReactCompositionContextCompound Components

Isi lesson

5 blok
  1. 1.
    Saat beberapa bagian selalu bekerja sebagai satu unitBelum selesaiWajib
  2. 2.
    Tabs kecil dengan state yang dibagikan melalui contextBelum selesaiWajib
  3. 3.
    Context dibatasi pada pola yang membutuhkannyaBelum selesaiWajib
  4. 4.
    Coding practiceBelum selesaiWajib
  5. 5.
    RingkasanBelum selesaiWajib

Saat beberapa bagian selalu bekerja sebagai satu unit

Wajib

Compound components adalah beberapa component kecil yang membentuk satu pola UI dan berbagi koordinasi dari parent. Tabs adalah contoh yang mudah: Tabs menyimpan item aktif, TabsList menampung trigger, TabsTrigger meminta perubahan pilihan, dan TabsPanel menampilkan content yang sesuai.

Pola ini berguna ketika beberapa bagian memang selalu memiliki hubungan yang sama, tetapi isi dan susunannya perlu fleksibel di tempat pemakaian. Ia bukan alasan untuk memecah satu component sederhana menjadi banyak file. Mulailah dari pola yang sudah berulang dan memiliki state atau aturan bersama yang nyata.

Bagian ini memengaruhi progres lesson.

Tabs kecil dengan state yang dibagikan melalui context

Wajib
tsx
import { createContext, useContext, useState, type ReactNode } from "react";

type TabsContextValue = {
  activeValue: string;
  setActiveValue: (value: string) => void;
};

const TabsContext = createContext<TabsContextValue | null>(null);

function useTabs() {
  const value = useContext(TabsContext);

  if (!value) {
    throw new Error("Tabs child harus dipakai di dalam Tabs.");
  }

  return value;
}

function Tabs({ defaultValue, children }: { defaultValue: string; children: ReactNode }) {
  const [activeValue, setActiveValue] = useState(defaultValue);

  return (
    <TabsContext.Provider value={{ activeValue, setActiveValue }}>
      <section>{children}</section>
    </TabsContext.Provider>
  );
}

function TabsList({ children }: { children: ReactNode }) {
  return <div role="tablist">{children}</div>;
}

function TabsTrigger({ value, children }: { value: string; children: ReactNode }) {
  const { activeValue, setActiveValue } = useTabs();
  const isActive = activeValue === value;

  return (
    <button
      id={value}
      type="button"
      role="tab"
      aria-selected={isActive}
      aria-controls={value + "-panel"}
      onClick={() => setActiveValue(value)}
    >
      {children}
    </button>
  );
}

function TabsPanel({ value, children }: { value: string; children: ReactNode }) {
  const { activeValue } = useTabs();

  if (activeValue !== value) {
    return null;
  }

  return <section id={value + "-panel"} role="tabpanel" aria-labelledby={value}>{children}</section>;
}

export function CourseTabs() {
  return (
    <Tabs defaultValue="overview">
      <TabsList>
        <TabsTrigger value="overview">Overview</TabsTrigger>
        <TabsTrigger value="practice">Practice</TabsTrigger>
      </TabsList>
      <TabsPanel value="overview">Mulai dari tujuan module.</TabsPanel>
      <TabsPanel value="practice">Buka practice setelah memahami konsep.</TabsPanel>
    </Tabs>
  );
}

Tabs adalah pemilik state aktif. Child tidak menerima activeValue dari CourseTabs satu per satu; mereka membaca dan mengubah value melalui context yang hanya berlaku di dalam pattern Tabs. Di tempat pemakaian, susunan JSX tetap menunjukkan struktur UI sebenarnya. Pattern ini layak bila trigger dan panel berulang sebagai satu kelompok, bukan untuk dua button yang kebetulan berdampingan sekali.

Bagian ini memengaruhi progres lesson.

Catatan penting

Wajib

Context dibatasi pada pola yang membutuhkannya

Context di contoh ini bukan global state aplikasi. Ia hanya menjadi jalur koordinasi untuk child Tabs. Batasi context pada API component yang jelas agar consumer dapat memahami component mana yang harus dipakai bersama dan error penggunaan dapat ditemukan lebih awal.

Bagian ini memengaruhi progres lesson.

Coding practice

WajibDibuka di workspace khusus

Build course tabs compound pattern

Ubah tabs lokal menjadi compound components yang berbagi active value melalui context kecil di dalam pattern Tabs.

Tujuan awal: Fokus di tab TSX.

Practice ini dibuka di workspace khusus. Buka practice untuk memakai editor, preview, dan cek otomatis.

Tombol selesai aktif setelah semua validasi wajib lolos.

8 cek otomatis5 checklist
Belum selesaiBuka practice

Ringkasan

Wajib
  • Compound components membantu saat beberapa bagian UI memiliki state dan aturan bersama.
  • Parent pattern menyimpan koordinasi; child menjaga API JSX tetap mudah dibaca.
  • Context lokal bukan pengganti state management global.
  • Berikutnya, kamu akan menggunakan children dan slot-like props untuk fleksibilitas layout tanpa context.

Bagian ini memengaruhi progres lesson.

Langkah berikutnya

Selesaikan bagian penting lesson ini

Lanjutkan blok wajib berikutnya: Saat beberapa bagian selalu bekerja sebagai satu unit.