Contoh

Pola penggunaan nyata untuk Tide v1.2.

Shorthand URL

Ganti boilerplate fetcher panjang dengan string url sederhana. Handler bawaan sudah termasuk credentials, abort, dan deteksi AuthError.

tsx
const gateways = createTide({
key: 'gateways',
url: '/api/gateways',
wsPath: 'data.hermes.gateways',
})

ETag / fetch kondisional

Aktifkan etag untuk mengirim header If-None-Match. Pada 304, Tide lewati update — tanpa bandwidth, tanpa re-render.

tsx
const tooling = createTide({
key: 'tooling',
url: '/api/agentic/tooling',
etag: true,
pollInterval: 15000,
})

Deduplikasi konten

hashCompare menggunakan hashing djb2 untuk melewati update reaktif saat data identik — mencegah rekonsiliasi DOM yang tidak perlu.

tsx
const stack = createTide({
key: 'stack',
url: '/api/stack/status',
hashCompare: true,
pollInterval: 5000,
})

Key reaktif (route dinamis)

Berikan fungsi getter untuk key dan url. Tide otomatis re-fetch saat salah satu berubah.

tsx
const [query, setQuery] = createSignal('react')

const results = createTide({
key: () => `search-${query()}`,
url: () => `/api/search?q=${query()}`,
})

Key reaktif — filter/tab switching

Saat menggunakan reactive key untuk UI tab atau filter, setiap key memiliki cache entry sendiri. Switch tab mengambil data baru (atau hit cache jika masih dalam cacheTime), dan loading state reset per key.

tsx
const [period, setPeriod] = createSignal<"today" | "24h" | "7d" | "30d">("today")

const chart = createTide<ChartResponse>({
key: () => `usage-chart-${period()}`,
url: () => `/api/usage/chart?period=${period()}`,
staleTime: 30_000,
cacheTime: 300_000,
persist: true,
})

// Each period gets its own cache entry:
// - "usage-chart-today" → cached separately
// - "usage-chart-24h" → cached separately

// UI: skeleton while loading, instant on cache hit
return (
<div>
<div class="flex gap-1">
<For each={["today", "24h", "7d", "30d"] as const}>
{(p) => (
<button
class={period() === p ? "active" : ""}
onClick={() => setPeriod(p)}
>
{p}
</button>
)}
</For>
</div>

<Show when={!chart.loading() && chart.data()} fallback={<ChartSkeleton />}>
<Chart data={chart.data()!} />
</Show>
</div>
)
Perilaku key: kunjungan pertama = loading + skeleton, kunjungan ulang dalam cacheTime = instan (0ms) dari sessionStorage, kunjungan ulang setelah cacheTime = fetch baru. Push WebSocket update key mana pun yang cocok dengan nilai reaktif saat ini. persist: true bertahan saat refresh halaman.

Fetch kondisional (enabled)

Gunakan enabled untuk menjeda semua aktivitas (fetch, poll, WS) sampai kondisi terpenuhi.

tsx
const [loggedIn, setLoggedIn] = createSignal(false)

const data = createTide({
key: 'private',
url: '/api/private',
enabled: () => loggedIn(),
})

Shorthand wsPath

Gunakan wsPath sebagai pengganti fungsi ws untuk ekstraksi dot-notation sederhana dari pesan WebSocket.

tsx
// Before (v1.0)
ws: (msg) => msg?.data?.stack ?? null

// After (current — standard)
wsPath: 'data.stack'

WS backoff + heartbeat

tsx
<TideProvider
ws={{ url: 'wss://server/ws' }}
reconnect={{ baseMs: 1000, maxMs: 30000 }}
heartbeat={25000}
>
<App />
</TideProvider>

pause/resume lifecycle

BARU di v1.2.0. Gunakan pause() sebelum optimistic mutation untuk menghentikan polling dan membatalkan request yang sedang berjalan. Panggil resume() + await refresh() setelah operasi selesai untuk sync ulang dengan server.

tsx
async function handleStart() {
tide.pause() // stop polling, prevent overwrite
tide.mutate(prev => ({ ...prev, status: 'starting' }))
await fetch('/api/start', { method: 'POST' })
tide.resume() // restart polling
await tide.refresh() // wait for fresh data
// UI now reflects real server state
}
Tanpa pause(), interval polling Tide bisa menimpa optimistic state di tengah operasi. Selalu pasang resume() dengan await refresh() untuk memastikan data converge sebelum unlock UI.