Untuk merender daftar, Solid punya dua komponen bawaan: <For> dan <Index>. Keduanya menerima array lewat prop each dan sebuah fungsi yang mengubah tiap item jadi elemen. Bedanya ada di cara mereka mengenali baris: <For> mengenali baris dari itemnya, <Index> dari posisinya. Bayangin rak di Toko Buku Kak Nadia, dan Kak Nadia menempel catatan kecil "kado" untuk Laskar Pelangi. Cara For: catatannya ditempel di bukunya, jadi saat buku-buku disusun ulang, catatan itu ikut pindah bersama Laskar Pelangi. Cara Index: catatannya ditempel di sekat rak nomor 1, jadi saat buku disusun ulang, catatan itu tetap di sekat 1, di sebelah buku lain.
🧪 Tebakan cepat: daftar buku dirender dengan
<Index>, tiap baris punya kotak catatan, dan kamu mengetikkadodi baris pertama, Laskar Pelangi. Lalu urutannya dibalik. Catatankadosekarang di sebelah Laskar Pelangi (baris 3) atau Cantik Itu Luka (baris 1)? Jawabannya ada di bagian "For vs Index saat urutannya berubah".
For: satu baris per item
import { createSignal, For } from "solid-js"
function App() {
const [buah] = createSignal(["Apel", "Mangga", "Jeruk"])
return (
<ul>
<For each={buah()}>
{(item) => <li>{item}</li>}
</For>
</ul>
)
}
Hasilnya satu <ul> berisi <li>Apel</li>, <li>Mangga</li>, <li>Jeruk</li>, sesuai urutan datanya.
Fordiimpor dari"solid-js".each={buah()}adalah array-nya. Signal-nya dipanggil pakai kurung.- Isi
<For>adalah fungsi:(item) => <li>{item}</li>. Solid memanggilnya sekali untuk tiap item, danitemadalah nilainya langsung, jadi ditulis{item}tanpa kurung. - Parameter kedua adalah nomor urutnya, berupa getter:
(item, i) => <li>{i() + 1}. {item}</li>menghasilkan1. Apel,2. Mangga,3. Jeruk.
buah().map(item => <li>{item}</li>) juga tampil sama, tapi tiap kali array-nya berubah, .map() membuat ulang semua baris. <For> cuma membuat baris untuk item yang baru. Latihan pertama memeriksa bahwa barisnya lahir dari <For>.
Index: satu baris per posisi
import { createSignal, Index } from "solid-js"
function App() {
const [numbers] = createSignal([10, 20, 30])
return (
<ul>
<Index each={numbers()}>
{(num, i) => <li>{i + 1}. {num()}</li>}
</Index>
</ul>
)
}
Hasilnya 1. 10, 2. 20, 3. 30. Peran kedua parameternya kebalikan dari For:
<For> |
<Index> |
|
|---|---|---|
| Baris dikenali dari | itemnya (objek yang sama) | posisinya (urutan ke berapa) |
| Parameter pertama | nilai: item |
getter: num() |
| Parameter kedua | getter: i() |
angka biasa: i |
| Cocok untuk | daftar objek yang bisa diurutkan, ditambah, dihapus | daftar yang posisinya tetap tapi isinya berubah |
Ini latihan kedua. Kalau angka di posisi 2 diganti dari 20 jadi 25, Index cuma mengganti teks di baris 2. For membuat baris baru, karena 25 adalah item yang belum pernah ia lihat.
For vs Index saat urutannya berubah
Daftar buku Toko Buku Kak Nadia, dengan kotak catatan di tiap baris:
import { createSignal, For } from "solid-js"
function App() {
const [buku, setBuku] = createSignal([
{ judul: "Laskar Pelangi", harga: 89000 },
{ judul: "Bumi Manusia", harga: 120000 },
{ judul: "Cantik Itu Luka", harga: 95000 },
])
const balik = () => setBuku(b => [...b].reverse())
const diskon = () => setBuku(b => b.map(x => x.judul === "Laskar Pelangi" ? { ...x, harga: 79000 } : x))
return (
<div>
<button onClick={balik}>Balik urutan</button>
<button onClick={diskon}>Diskon Laskar Pelangi</button>
<ul>
<For each={buku()}>
{(b, i) => (
<li>
{i() + 1}. {b.judul} · Rp{b.harga}
<input placeholder="catatan" />
</li>
)}
</For>
</ul>
</div>
)
}
Versi Index-nya sama, dengan <Index each={buku()}>, {i + 1}, {b().judul}, dan {b().harga}. Ketik kado di baris Laskar Pelangi, lalu klik Balik urutan. Diuji di Solid 1.9:
<For> |
<Index> |
|
|---|---|---|
| Teks sesudah dibalik | 1. Cantik Itu Luka, 2. Bumi Manusia, 3. Laskar Pelangi |
sama |
Elemen <li> |
dipindah, ikut bukunya | diam di tempat, teksnya diganti |
Catatan kado |
di baris Laskar Pelangi, sekarang nomor 3 | di baris 1, sebelah Cantik Itu Luka |
| Baris yang dibuat baru | 0 | 0 |
Dengan Index, kado tetap di baris pertama, dan sekarang ada di sebelah Cantik Itu Luka. Itu jawaban tebakannya. Barisnya gak pernah pindah, cuma teks di dalamnya yang diganti.
Satu hal lagi tentang For: dia mengenali item dari objeknya, bukan dari isinya. Tombol Diskon Laskar Pelangi mengganti objeknya dengan objek baru, { ...x, harga: 79000 }, dan For menganggapnya item baru: barisnya dibuat ulang dan catatan kado hilang. Index cuma mengganti teks harganya jadi Rp79000.
⚠️ Jebakan yang sering ketemu
- Tertukar kurung. Di
For, item itu nilai:{b().judul}diForberhenti denganTypeError: b is not a function. Nomor urutnya getter:{i + 1}diFortampilfunction () { [native code] }1. DiIndexkebalikannya:{num()}dan{i + 1}. - Menulis barisnya satu per satu. Tiga
<li>yang diketik tampil benar, tapi gak mengikuti datanya. Latihan pertama memeriksa ada<lidi dalam<For each=...>, dan latihan kedua memeriksa isi<li>diawali{. - Memakai
.map(). Jalan, tapi membuat ulang semua baris tiap array berubah, dan latihan pertama menilaiFor. - Lupa pembungkus. Baris
<li>ditaruh di dalam satu<ul>, karena yang dicekul li:first-childdanul li:last-child.
TL;DR: <For each={buah()}>{(item, i) => <li>{item}</li>}</For> membuat satu baris per item: item berupa nilai, nomor urut berupa getter i(), dan barisnya dikenali dari objeknya, jadi saat urutan berubah elemennya ikut pindah bersama isinya (dan objek baru berarti baris baru). <Index each={numbers()}>{(num, i) => <li>{i + 1}. {num()}</li>}</Index> kebalikannya: item berupa getter num(), nomor urut berupa angka, dan barisnya terikat ke posisi, jadi yang berubah cuma teksnya. Pakai For untuk daftar objek yang diurutkan, ditambah, dihapus; Index untuk daftar yang posisinya tetap tapi isinya berganti.