<Portal> merender sepotong JSX di tempat lain di DOM, biasanya langsung di document.body, padahal di kodemu dia tetap anak komponen yang menulisnya. <Dynamic> merender tag atau komponen yang baru dipilih saat aplikasinya jalan. Bayangin Kak Nadia menulis pengumuman promo di meja kasir, tapi menempelnya di papan besar dekat pintu masuk, supaya gak tertutup rak mana pun. Yang menulis tetap kasir, yang menempel tetap di papan. Dynamic itu seperti info buku yang sama dicetak jadi poster besar atau label kecil, tergantung pilihan saat itu.
🧪 Tebakan cepat: modal detail buku dirender lewat
<Portal>kedocument.body.<div class="kartu">yang membungkus Portal-nya punyaonClick. Kamu mengklik teks di dalam modal.onClickdi kartu jalan atau gak? Jawabannya ada di bagian "Event tetap ikut pohon komponen".
Masalahnya: kartu yang memotong modal
Kartu buku di toko memakai overflow: hidden, supaya sampulnya ikut sudut kartu yang membulat. Modal detail yang ditulis di dalam kartu ikut terpotong di tepi kartu itu, dan z-index setinggi apa pun gak menolong, karena dia terkurung di dalam kartu. Modal, toast, tooltip, dan dropdown butuh keluar dari kotak induknya. Itu tugas Portal.
Portal dan mount
import { createSignal, Show } from "solid-js"
import { Portal } from "solid-js/web"
function KartuBuku(props) {
const [buka, setBuka] = createSignal(false)
return (
<div class="kartu" onClick={() => console.log("kartu menerima klik")}>
<h3>{props.judul}</h3>
<button onClick={() => setBuka(true)}>Lihat detail</button>
<Show when={buka()}>
<Portal>
<div class="modal">
<p>{props.judul} · Rp89.000 · stok 4</p>
<button onClick={() => setBuka(false)}>Tutup</button>
</div>
</Portal>
</Show>
</div>
)
}
Diuji di Solid 1.9.17, sesudah Lihat detail diklik, DOM-nya:
<body>
<div id="root">
<div class="kartu"><h3>Laskar Pelangi</h3><button>Lihat detail</button></div>
</div>
<div><div class="modal"><p>Laskar Pelangi · Rp89.000 · stok 4</p><button>Tutup</button></div></div>
</body>
Portaldiimpor dari"solid-js/web", bukan dari"solid-js".- Tanpa prop apa pun, isinya dipasang di
document.body, di dalam satu<div>buatan Portal. Kartunya gak lagi memotong modal. - Prop
mountmemilih tempat lain:<Portal mount={document.getElementById("modal-root")}>. - Saat
Showmenutupnya,<div>itu ikut dicabut daribody. - Karena modalnya bukan lagi anak
.kartudi DOM, CSS seperti.kartu .modal { ... }gak berlaku untuknya. Beri modal kelas dan gayanya sendiri, misalnyaposition: fixed.
Event tetap ikut pohon komponen
Di DOM, modal itu anak body. Di kodemu, dia anak KartuBuku. Solid mengikuti yang kedua. Diuji di Solid 1.9.17: klik teks di dalam modal menjalankan onClick di .kartu dan mencetak kartu menerima klik. Itu jawaban tebakannya.
Sebabnya: onClick di Solid didelegasikan, cukup satu listener di document yang menelusuri ke atas dari elemen yang diklik. Sampai di <div> buatan Portal, penelusurannya melompat ke tempat <Portal> ditulis, lalu lanjut ke .kartu. Listener asli lewat on:click atau addEventListener di .kartu gak mendengarnya, karena di DOM jalurnya modal, <div>, lalu body. Context juga tetap sampai: useContext di dalam Portal membaca Provider di sekitar <Portal>.
Dynamic: tag atau komponen yang dipilih saat jalan
Bentuk latihan pelajaran ini:
import { createSignal } from "solid-js"
import { Dynamic } from "solid-js/web"
function App() {
const [tag, setTag] = createSignal("h1")
return (
<div>
<Dynamic component={tag()}>Heading Dinamis</Dynamic>
<button onClick={() => setTag(t => t === "h1" ? "h2" : "h1")}>
Toggle Tag
</button>
</div>
)
}
| Kejadian | tag() |
Yang tampil |
|---|---|---|
| Awal | "h1" |
<h1>Heading Dinamis</h1> |
| Klik sekali | "h2" |
<h2>Heading Dinamis</h2> |
| Klik lagi | "h1" |
<h1>Heading Dinamis</h1> |
component={tag()}menerima nama tag sebagai string. Tulisannya tetap, yang berubah cuma jenis elemennya.t === "h1" ? "h2" : "h1"membuatnya bolak-balik: klik kedua mengembalikannya keh1.
component juga menerima komponen. Toko bisa menampilkan buku sebagai kartu grid atau baris daftar:
const tampilan = { grid: KartuGrid, baris: KartuBaris }
<Dynamic component={tampilan[mode()]} judul="Laskar Pelangi" stok={stok()} />
Prop lain, judul dan stok, diteruskan ke komponen yang terpilih dan tetap reaktif. Diuji di Solid 1.9.17: mengganti mode membuat komponen yang baru, mengubah stok cuma mengganti angkanya tanpa membuat ulang komponen.
⚠️ Jebakan yang sering ketemu
- Impor dari tempat yang salah.
PortaldanDynamicada di"solid-js/web"."solid-js"gak punya ekspor dengan nama itu, jadi impornya gagal. component={tag}tanpa kurung. Yang dikirim fungsi signal-nya, dan Dynamic menganggapnya komponen. Diuji di Solid 1.9.17: yang tampil cuma teksh1, headingnya hilang. Tuliscomponent={tag()}.- Mengira CSS induk ikut ke Portal. Di DOM, isi Portal ada di
body, jadi selector yang bergantung pada.kartugak kena. - Penukar di latihan. Penilainya mengklik
<button>pertama sekali dan dua kali. TulisanHeading Dinamisharus sama dih1danh2.
TL;DR: <Portal> dari "solid-js/web" memasang isinya di document.body (atau di elemen pilihan lewat mount={...}), keluar dari kotak induk yang memotongnya, tapi tetap bagian dari pohon komponen: onClick di komponen induk, context, dan Show di sekitarnya tetap berlaku. <Dynamic component={tag()}> merender tag atau komponen yang dipilih saat jalan, meneruskan prop lain, dan membuat ulang isinya cuma saat komponennya berganti. Latihannya: Heading Dinamis jadi h2 sesudah satu klik dan kembali h1 sesudah dua klik.