Memo adalah nilai turunan yang di-cache: nilai yang dihitung dari signal lain, disimpan, dan cuma dihitung ulang kalau signal sumbernya berubah. createMemo(() => count() * 2) mengembalikan getter, jadi dibaca seperti signal: doubled(). Bayangin Kak Nadia mencari buku yang judulnya mengandung kata tertentu, lalu menulis hasilnya di papan kecil dekat kasir. Siapa pun yang bertanya cukup membaca papan itu. Kak Nadia baru menyusuri rak lagi kalau kata pencariannya berganti. Fungsi biasa itu kebalikannya: tiap orang yang bertanya membuat Kak Nadia menyusuri rak dari awal.
🧪 Tebakan cepat: daftar hasil pencarian dibuat dengan fungsi biasa,
const hasil = () => { console.log("filter jalan"); return buku.filter(...) }, dan dibaca di dua paragraf. Kamu mengetik satu huruf di kotak cari.filter jalantercetak berapa kali, 1 atau 2? Jawabannya ada di bagian "Fungsi biasa vs createMemo".
createMemo: hitung sekali, baca berkali-kali
import { createSignal, createMemo } from "solid-js"
function App() {
const [count, setCount] = createSignal(3)
const doubled = createMemo(() => count() * 2)
return (
<div>
<p>{count()} x 2 = {doubled()}</p>
</div>
)
}
Hasilnya <p>3 x 2 = 6</p>.
createMemo(() => count() * 2)menerima fungsi penghitung. Solid langsung menjalankannya sekali, menyimpan hasilnya (6), dan mencatat signal yang dibacanya (count).doubledadalah getter. Dibaca dengan kurung,{doubled()}, persis seperti signal. Membacanya gak menghitung ulang, cuma mengambil nilai yang tersimpan.- Saat
countberubah, misalnya jadi4, fungsi penghitungnya jalan sekali lagi dan tempat yang membacadoubled()ikut berubah:4 x 2 = 8. - Memo gak punya setter. Nilainya selalu hasil hitungan dari sumbernya.
Itu latihan pertama: count mulai dari 3, doubled sebagai memo, dan paragraf yang merangkai keduanya.
Fungsi biasa vs createMemo
Kotak pencarian Toko Buku Kak Nadia, dengan dua nilai turunan: hasil pencarian dan total keranjang.
import { createSignal, createMemo } from "solid-js"
const buku = [
{ judul: "Laskar Pelangi", harga: 89000 },
{ judul: "Bumi Manusia", harga: 120000 },
{ judul: "Cantik Itu Luka", harga: 95000 },
]
function App() {
const [cari, setCari] = createSignal("")
const [jumlah, setJumlah] = createSignal(0)
const hasil = createMemo(() => {
console.log("filter jalan")
return buku.filter(b => b.judul.toLowerCase().includes(cari().toLowerCase()))
})
const total = createMemo(() => {
console.log("total dihitung")
return jumlah() * 89000
})
return (
<div>
<input value={cari()} onInput={e => setCari(e.target.value)} placeholder="Cari judul" />
<p>Hasil: {hasil().map(b => b.judul).join(", ")}</p>
<p>{hasil().length} buku ditemukan</p>
<button onClick={() => setJumlah(j => j + 1)}>+1 Buku</button>
<p>Total: Rp{total()}</p>
<p>Gratis ongkir: {total() >= 150000 ? "ya" : "belum"}</p>
</div>
)
}
hasil() dibaca di dua paragraf, total() juga. Ini isi console-nya, dibandingkan dengan versi fungsi biasa (const hasil = () => { ... } dan const total = () => { ... }), diuji di Solid 1.9:
| Kejadian | Dengan createMemo |
Dengan fungsi biasa |
|---|---|---|
| Halaman dibuka | filter jalan 1×, total dihitung 1× |
filter jalan 2×, total dihitung 2× |
Ketik b |
filter jalan 1× |
filter jalan 2× |
Klik +1 Buku |
total dihitung 1× |
total dihitung 2× |
Fungsi biasa jalan sekali per tempat yang membacanya, jadi satu huruf membuat filter jalan tercetak 2 kali. Itu jawaban tebakannya. Memo jalan sekali per perubahan, berapa pun yang membacanya. Hasilnya sama di layar: Hasil: Bumi Manusia, 1 buku ditemukan. Yang beda cuma berapa kali kerjanya diulang.
Perhatikan juga: mengetik gak menjalankan total, dan klik gak menjalankan filter. Masing-masing cuma mengikuti signal yang dibacanya.
Signal, memo, atau effect?
| Pakai | Untuk | Contoh |
|---|---|---|
createSignal |
nilai yang kamu ubah sendiri lewat setter | isi kotak cari, jumlah di keranjang |
createMemo |
nilai yang dihitung dari signal lain, read-only | hasil filter, total harga |
createEffect |
kerja di luar tampilan | simpan ke localStorage, document.title |
Fungsi biasa seperti () => harga() * 0.9 tetap boleh untuk hitungan murah yang dibaca di satu tempat. Begitu hitungannya berat atau dibaca di banyak tempat, jadikan memo.
Latihan kedua: ganjil atau genap
import { createSignal, createMemo } from "solid-js"
function App() {
const [count, setCount] = createSignal(5)
const isEven = createMemo(() => count() % 2 === 0)
return (
<div>
<p>{count()} is {isEven() ? "Genap" : "Ganjil"}</p>
<button onClick={() => setCount(c => c + 1)}>+1</button>
</div>
)
}
count() % 2 === 0bernilaitruekalau angkanya genap. Untuk5, hasilnyafalse, jadi paragrafnya5 is Ganjil.- Klik
+1:countjadi6, memonya menghitung ulang jaditrue, dan paragrafnya berubah sendiri jadi6 is Genap.
💡 Memo cuma memberi tahu kalau nilainya berubah
Memo menyimpan hasil terakhir dan membandingkannya dengan hasil baru. Kalau sama, gak ada yang diberi tahu. Misalnya const adaStok = createMemo(() => stok() > 0): stok turun dari 4 ke 3, memonya menghitung ulang, hasilnya tetap true, jadi teks yang membaca adaStok() gak disentuh. Baru saat stok jadi 0 hasilnya berubah ke false dan teksnya ikut.
⚠️ Jebakan yang sering ketemu
- Membaca memo tanpa kurung. Memo itu getter, jadi tulis
{doubled()}. Latihan pertama memeriksa bahwa kodemu menampilkan memonya dengan bentuk{doubled()}, gak jauh sesudah bariscreateMemo. - Mengetik hasilnya langsung.
<p>3 x 2 = 6</p>tampil benar, tapi gak mengikuticount, dan penilaian mencari{doubled()}di kodenya. - Efek + setter untuk nilai turunan.
createEffect(() => setDoubled(count() * 2))jalan, tapi butuh signal tambahan dan satu putaran update ekstra, dan gampang jadi loop. Nilai turunan tempatnya dicreateMemo. - Lupa import.
createMemodiimpor dari"solid-js"bersamacreateSignal:import { createSignal, createMemo } from "solid-js".
TL;DR: const doubled = createMemo(() => count() * 2) membuat nilai turunan yang di-cache: dihitung sekali saat dibuat, dihitung ulang cuma saat signal sumbernya berubah, lalu dibaca sebagai {doubled()} berapa kali pun tanpa menghitung lagi. Fungsi biasa jalan sekali per tempat yang membacanya: hasil filter yang dibaca di dua paragraf difilter dua kali per ketikan, dengan memo sekali. Memo read-only dan cuma memberi tahu pembacanya kalau hasilnya berubah. Signal untuk nilai yang kamu ubah, memo untuk nilai yang dihitung, effect untuk kerja di luar tampilan.