SolidStart Data — SolidJS

SolidStart menyediakan primitives untuk data loading dan mutations. createAsync import { createAsync } from "@solidjs/router" const getUsers = cache(async ()…

Di SolidStart, data toko disimpan di server, dan halaman memintanya lewat tiga alat dari @solidjs/router: query untuk fungsi pengambil data, createAsync untuk membacanya di komponen, dan action untuk mengubahnya. Fungsi yang ditandai "use server" cuma jalan di server. Bayangin kasir Toko Buku Kak Nadia dan gudangnya. Kasir (halaman) gak boleh membuka lemari gudang (database) sendiri, jadi dia menelepon gudang. Jawaban gudang dicatat di kertas kecil di meja kasir, supaya dua pembeli yang menanyakan hal yang sama gak bikin dua telepon. Waktu ada pesanan, kasir mengirim slip ke gudang, lalu menelepon lagi untuk angka stok terbaru.

🧪 Tebakan cepat: daftar buku dimuat dengan createAsync(() => getKatalog()). Kamu menekan Tambah di Laskar Pelangi (stok 4), dan action-nya mengurangi stok di server. Kamu gak menulis kode apa pun untuk memuat ulang daftarnya. Sesudah action selesai, daftarnya menampilkan stok 3, atau tetap 4? Jawabannya ada di bagian "Sesudah action: revalidasi".

"use server": kode yang cuma jalan di server

// src/lib/toko.ts
import { query } from "@solidjs/router"
import { db } from "./db"

export const getKatalog = query(async () => {
  "use server"
  return db.semuaBuku()
}, "katalog")

query dan createAsync: membaca data di halaman

// src/routes/index.tsx
import { createAsync } from "@solidjs/router"
import { For, Suspense } from "solid-js"
import { getKatalog } from "~/lib/toko"

export default function Beranda() {
  const buku = createAsync(() => getKatalog())

  return (
    <Suspense fallback={<p>Memuat katalog...</p>}>
      <ul>
        <For each={buku()}>{(b) => <li>{b.judul} · stok {b.stok}</li>}</For>
      </ul>
    </Suspense>
  )
}

Diuji dengan @solidjs/router 1.0 dan server palsu yang menjawab 800 ms kemudian:

Waktu buku() Halaman
0 ms undefined, getKatalog dipanggil Memuat katalog...
800 ms array 3 buku Laskar Pelangi · stok 4, Bumi Manusia · stok 2, Cantik Itu Luka · stok 0

action: mengubah data lewat form

import { action, useSubmission } from "@solidjs/router"

export const tambahKeKeranjang = action(async (formData) => {
  "use server"
  const id = Number(formData.get("id"))
  const buku = await db.cariBuku(id)
  if (buku.stok === 0) throw new Error("Stok habis")
  await db.tambahKeKeranjang(id)
}, "tambahKeKeranjang")

Di halaman, tiap buku punya form kecil:

const kirim = useSubmission(tambahKeKeranjang)

<Show when={kirim.pending}><p>Menambahkan...</p></Show>
<Show when={kirim.error}><p>Gagal: {kirim.error.message}</p></Show>
<form action={tambahKeKeranjang} method="post">
  <input type="hidden" name="id" value={b.id} />
  <button type="submit">Tambah</button>
</form>

Sesudah action: revalidasi

Kamu menekan Tambah di Laskar Pelangi. Action-nya 300 ms, getKatalog 800 ms, getKeranjang 200 ms. Diuji dengan @solidjs/router 1.0:

Sejak klik Yang terjadi Halaman
0 ms form dikirim, action jalan di server Menambahkan..., daftar lama tetap
300 ms action selesai, router memanggil lagi getKatalog dan getKeranjang masih daftar lama
1.100 ms data baru datang Laskar Pelangi · stok 3, Keranjang: 1 buku, Menambahkan... hilang

Stoknya turun jadi 3 sendiri. Itu jawaban tebakannya. Sesudah action berhasil, router merevalidasi (memuat ulang) semua query di halaman itu, jadi daftar dan keranjang cocok lagi dengan server. Selama itu daftar lama tetap tampil, fallback gak muncul lagi.

Latihan: query dan createAsync di sandbox

Sandbox latihan gak punya server SolidStart, tapi query dan createAsync di sana bekerja seperti di @solidjs/router: pemanggilan dengan argumen yang sama berbagi satu request, dan createAsync menahan <Suspense> sampai datanya datang. Fungsi "use server" jalan di pratinjau.

const getItems = query(async () => {
  "use server"
  setPermintaan((n) => n + 1)
  await new Promise((r) => setTimeout(r, 200))
  return [
    { id: 1, name: "Item 1" },
    { id: 2, name: "Item 2" },
  ]
}, "items")

function Daftar() {
  const items = createAsync(() => getItems())
  return (
    <ul>
      <For each={items()}>{(item) => <li>{item.name}</li>}</For>
    </ul>
  )
}

Komponen Jumlah memanggil createAsync(() => getItems()) juga, tapi penghitungnya tetap Permintaan ke server: 1: query membagi jawabannya ke dua komponen. Tanpa query, fungsi yang sama ditanya dua kali.

⚠️ Jebakan yang sering ketemu

TL;DR: Fungsi dengan "use server" di baris pertamanya cuma jalan di server; browser memanggilnya lewat request. query(fungsi, "katalog") membungkus pengambil data dan menyimpan hasilnya per nama, dan createAsync(() => getKatalog()) membacanya di halaman: undefined dulu, dibaca di dalam <Suspense>. action(fungsi, "nama") menerima FormData dari <form action={...} method="post">, useSubmission memberi pending dan error, dan sesudah action berhasil router merevalidasi semua query di halaman, jadi stok dan keranjang ikut berubah sendiri. Di sandbox latihan, query dan createAsync bekerja sama, dan fungsi "use server" jalan di pratinjau.

Yang akan kamu pelajari