ReactJS

Belum masuk. Progresmu tidak tersimpan.

Masuk
  • Bab 4 dari 10
  • 35 menit
  • 1 latihan kode
  • 4 soal kuis

Props, merender list dengan key, dan rendering bersyarat

Di bab ini (7 bagian)
  1. Tujuan
  2. Props: parameter untuk komponen
  3. Props itu read-only
  4. Merender list dengan map
  5. Rendering bersyarat
  6. Kesalahan umum
  7. Rangkuman

Tujuan bab ini

  • Mengirim data ke komponen lewat props, memakai destructuring, nilai default, dan children.
  • Memahami kenapa props bersifat read-only dan mengalir satu arah.
  • Merender list dengan map dan memberi key yang tepat.
  • Menampilkan elemen secara bersyarat dengan &&, ternary, dan early return.

Props: parameter untuk komponen

Komponen yang isinya selalu sama kurang berguna. Props (singkatan dari properties) membuat satu komponen bisa menampilkan data berbeda, persis seperti parameter pada fungsi.

function KartuMahasiswa(props) {
  return (
    <div className="kartu">
      <h3>{props.nama}</h3>
      <p>NIM: {props.nim}</p>
    </div>
  );
}

function Daftar() {
  return (
    <>
      <KartuMahasiswa nama="Rina" nim="20101" />
      <KartuMahasiswa nama="Budi" nim="20102" />
    </>
  );
}
// Tampil dua kartu: Rina (20101) dan Budi (20102)

Di balik layar, React mengumpulkan semua atribut menjadi satu objek lalu memberikannya sebagai argumen pertama: KartuMahasiswa({ nama: "Rina", nim: "20101" }).

Props bisa berisi tipe apa pun. Teks bisa ditulis dengan tanda kutip, tapi selain string kamu wajib memakai {}:

<Produk
  nama="Laptop"            // string
  harga={8500000}          // number
  tersedia={true}          // boolean (cukup tulis: tersedia)
  tag={["baru", "promo"]}  // array
  onBeli={() => alert("Dibeli")} // fungsi
/>

Hati-hati: harga="8500000" mengirim string, bukan angka.

Destructuring dan nilai default

Menulis props. berulang kali melelahkan. Cara yang lazim adalah destructuring langsung di parameter, sekaligus memberi nilai default untuk props yang boleh kosong:

function Tombol({ teks = "Simpan", warna = "hitam" }) {
  return <button className={warna}>{teks}</button>;
}

<Tombol />                  // <button class="hitam">Simpan</button>
<Tombol teks="Kirim" />     // <button class="hitam">Kirim</button>

Nilai default hanya dipakai saat prop tidak dikirim atau bernilai undefined. Kalau kamu mengirim null, default tidak dipakai.

children: isi di antara tag

Apa pun yang kamu tulis di antara tag pembuka dan penutup komponen dikirim sebagai prop khusus bernama children. Ini berguna untuk komponen pembungkus seperti kartu, modal, atau layout.

function Kotak({ judul, children }) {
  return (
    <section className="kotak">
      <h2>{judul}</h2>
      {children}
    </section>
  );
}

<Kotak judul="Pengumuman">
  <p>Kelas hari ini libur.</p>
  <p>Tugas dikumpulkan Jumat.</p>
</Kotak>
// Tampil: judul "Pengumuman" lalu dua paragraf di dalam section

Kotak tidak perlu tahu isinya apa. Ia cukup menyediakan bingkai.

Props itu read-only

Aturan emas: komponen tidak boleh mengubah props-nya sendiri.

function Harga({ nilai }) {
  nilai = nilai * 2; // jangan lakukan ini
  return <p>{nilai}</p>;
}

Kenapa? React mengharapkan komponen bersifat murni: input sama, output sama. Props adalah milik komponen induk. Kalau anak diam-diam mengubahnya, hasil render jadi tidak bisa ditebak dan bug-nya sulit dilacak.

Data di React mengalir satu arah: dari induk ke anak. Kalau anak perlu "mengubah" sesuatu, induk mengirim sebuah fungsi lewat props (misalnya onBeli), anak memanggilnya, lalu induk yang memperbarui state-nya. Kalau kamu butuh nilai turunan, buat variabel baru: const ganda = nilai * 2;.

Merender list dengan map

Data di aplikasi nyata hampir selalu berupa array: daftar produk, pesan, tugas. Di JSX tidak ada for di dalam {}, jadi kita memakai map() untuk mengubah setiap item menjadi elemen JSX.

const produk = [
  { id: 1, nama: "Laptop", harga: 8500000 },
  { id: 2, nama: "Mouse", harga: 150000 },
  { id: 3, nama: "Keyboard", harga: 320000 },
];

function DaftarProduk() {
  return (
    <ul>
      {produk.map((item) => (
        <li key={item.id}>
          {item.nama}: Rp{item.harga}
        </li>
      ))}
    </ul>
  );
}
// Tampil:
// • Laptop: Rp8500000
// • Mouse: Rp150000
// • Keyboard: Rp320000

map menghasilkan array elemen, dan React bisa langsung merender array di dalam {}. Kamu juga bisa menggabungkannya dengan filter atau toSorted sebelum dirender, misalnya hanya produk di bawah 500 ribu: produk.filter((p) => p.harga < 500000).map(...).

Kenapa butuh key?

Ingat reconciliation dari bab Virtual DOM. Saat list berubah, React perlu tahu item mana yang sama, mana yang baru, dan mana yang dihapus. key adalah "KTP" setiap item.

Aturan key:

  • Unik di antara saudaranya dalam list yang sama.
  • Stabil: item yang sama selalu punya key yang sama di setiap render.
  • Ditaruh di elemen terluar yang dikembalikan map, bukan di elemen di dalamnya.
  • key tidak ikut dikirim sebagai props; komponen anak tidak bisa membaca props.key.

Tanpa key, React menampilkan peringatan di console: Each child in a list should have a unique "key" prop.

Kenapa index itu buruk?

Godaan pemula adalah map((item, i) => <li key={i}>...). Ini aman hanya jika list tidak pernah diurutkan ulang, disisipi, atau dihapus sebagian.

Bayangkan list tugas ["Belajar", "Masak", "Olahraga"] dengan key index 0, 1, 2, dan setiap baris punya <input> untuk catatan. Kamu menghapus "Belajar". Sekarang "Masak" mendapat key 0 dan "Olahraga" key 1. React mengira item dengan key 0 dan 1 masih ada dan hanya teksnya yang berubah, lalu item key 2 yang dihapus. Akibatnya, catatan yang kamu ketik di baris "Belajar" sekarang muncul di baris "Masak".

Pilihan keyAman?
item.id dari databaseYa, paling baik
ID yang dibuat saat item ditambah (misalnya crypto.randomUUID())Ya
Index arrayHanya untuk list statis
Math.random() di dalam renderTidak, berubah setiap render

Rendering bersyarat

Sering kali sebuah elemen hanya tampil dalam kondisi tertentu. Ada tiga pola utama.

Early return dengan if

Paling jelas untuk percabangan besar, ditulis sebelum return utama:

function Profil({ user }) {
  if (!user) {
    return <p>Silakan masuk dulu.</p>;
  }
  return <h1>Halo, {user.nama}</h1>;
}

Komponen juga boleh return null agar tidak menampilkan apa-apa.

Ternary ? :

Ringkas untuk memilih satu dari dua tampilan di tengah JSX:

<p>{login ? "Halo, pengguna" : "Kamu belum masuk"}</p>

Operator &&

Menampilkan sesuatu hanya bila kondisinya benar, tanpa cabang "selain itu":

{keranjang.length > 0 && <span>{keranjang.length} item</span>}

Jebakan angka 0. a && b mengembalikan a bila a falsy. Kalau keranjang.length bernilai 0, ekspresi keranjang.length && <span>...</span> menghasilkan 0, dan React menampilkan angka 0 di layar. Selalu jadikan kondisi boolean dulu: keranjang.length > 0 && ....

KebutuhanPola
Seluruh komponen berbeda, atau data belum siapEarly return
Pilih satu dari dua di dalam JSXTernary
Tampil atau tidak sama sekali&& dengan kondisi boolean

Kesalahan umum

  • Mengubah props di dalam komponen anak, misalnya props.nama = "...".
  • Mengirim angka sebagai string, harga="100" alih-alih harga={100}.
  • Lupa key atau memakai index pada list yang bisa diurutkan dan dihapus.
  • Menaruh key di elemen dalam, bukan di elemen terluar hasil map.
  • Memakai && dengan angka, sehingga 0 tercetak di layar.
  • Lupa return di arrow function map yang memakai kurung kurawal: map((x) => { <li>{x}</li> }) menghasilkan undefined.

Rangkuman

  • Props adalah objek argumen komponen; pakai destructuring, nilai default, dan children untuk isi di antara tag.
  • Props read-only dan mengalir dari induk ke anak; anak meminta perubahan lewat fungsi callback.
  • List dirender dengan map, setiap elemen butuh key unik dan stabil, idealnya ID dari data.
  • Index sebagai key bisa membuat isi baris tertukar saat list berubah urutan atau dihapus.
  • Rendering bersyarat: early return untuk cabang besar, ternary untuk dua pilihan, && dengan kondisi boolean.

Selesaikan bab ini

  1. 1. Baca materi
  2. 2. Latihan kode (1)
  3. 3. Kuis (4 soal)

Latihan kode: Menyiapkan data list produk

Sebelum dirender dengan map, data biasanya disaring dan diurutkan dulu. Buat dua fungsi murni:

  1. siapkanDaftar(produk, maksHarga) menerima array { id, nama, harga } dan mengembalikan array baru berisi { key, label } untuk produk dengan harga <= maksHarga, diurutkan dari harga termurah. key adalah id dalam bentuk string, label berformat "Nama: RpHarga", misalnya "Mouse: Rp150000". Array produk asli tidak boleh berubah urutannya.
  2. labelKeranjang(jumlah) mengembalikan "N item" bila jumlah lebih dari 0, dan null bila 0. Ingat jebakan && dengan angka: komponen nanti cukup menulis {labelKeranjang(n)}, karena null tidak tampil apa-apa.

Di komponen, hasilnya dipakai seperti ini:

<ul>
  {siapkanDaftar(produk, 500000).map((p) => (
    <li key={p.key}>{p.label}</li>
  ))}
</ul>

Cek pemahaman

  1. 1Apa yang tampil di layar?

    function Keranjang({ items }) {
      return (
        <div>
          {items.length && <span>{items.length} item</span>}
        </div>
      );
    }
    
    // dirender sebagai:
    <Keranjang items={[]} />
  2. 2Kenapa index array buruk sebagai key pada list yang itemnya bisa dihapus?

  3. 3Teks dan elemen yang ditulis di antara tag pembuka dan penutup komponen diterima sebagai prop children.

  4. 4Apa teks kedua tombol, berurutan?

    function Tombol({ teks = "Simpan" }) {
      return <button>{teks}</button>;
    }
    
    function App() {
      return (
        <>
          <Tombol />
          <Tombol teks="Kirim" />
        </>
      );
    }