Composables Reference
RecachedPlugin
app.use(RecachedPlugin, options?: CacheOptions)Vue plugin that creates the cache and provides it to the entire app via inject. Install it before app.mount.
Options
| Option | Type | Description |
|---|---|---|
connect | { url: string; password?: string } | WebSocket URL of the Recached server and optional auth password. |
persistence | boolean | Load the IndexedDB WAL on startup; write every mutation through for cross-refresh persistence. |
broadcastChannel | string | BroadcastChannel name for cross-tab mutation sharing without a server. |
Examples
// With server connection
app.use(RecachedPlugin, { connect: { url: 'ws://localhost:6380' } })
// With persistence only (no server)
app.use(RecachedPlugin, { persistence: true })
// With cross-tab sync only
app.use(RecachedPlugin, { broadcastChannel: 'my-app' })
// Full setup
app.use(RecachedPlugin, {
persistence: true,
broadcastChannel: 'my-app',
connect: { url: 'wss://cache.example.com', password: 'secret' },
})useRecached()
function useRecached(): CacheReturns the Cache instance provided by RecachedPlugin. Use it to call write and imperative methods: set, setEx, setJSON, del, publish, subscribe, clearPersistence.
Throws if RecachedPlugin has not been installed.
Example
<script setup lang="ts">
import { useRecached } from '@recached/vue'
const cache = useRecached()
function save() {
cache.setJSON('user:42', { id: 42, name: 'Alice' }, 300)
}
</script>
<template>
<button @click="save">Save</button>
</template>Writing from event handlers
Reads (useKey, useKeyJSON) are reactive. Writes are always done imperatively via useRecached():
<script setup lang="ts">
import { useKey, useRecached } from '@recached/vue'
const cache = useRecached()
const count = useKey('count')
const n = computed(() => Number(count.value ?? 0))
</script>
<template>
<div>
<p>{{ n }}</p>
<button @click="cache.set('count', String(n + 1))">+</button>
<button @click="cache.set('count', String(n - 1))">−</button>
</div>
</template>useKey(key)
function useKey(key: string): Ref<string | null>Reactively reads a string value from the cache. Returns a Ref<string | null> — null when the key does not exist or has expired.
The ref updates automatically whenever key is mutated — from any source:
- A write in the same component or another component in the same tab
- A write received from the server (WebSocket fan-out)
- A write from another tab (BroadcastChannel sync)
The onMutation listener is cleaned up automatically via onUnmounted.
Example
<script setup lang="ts">
import { useKey } from '@recached/vue'
const status = useKey('system:status')
</script>
<template>
<span :class="`badge badge--${status ?? 'unknown'}`">
{{ status ?? 'unknown' }}
</span>
</template>Dynamic keys
Pass any reactive expression's resolved value; the composable reads the current key at call time. To track a dynamic key reactively, use watchEffect with useRecached:
<script setup lang="ts">
import { watchEffect, ref } from 'vue'
import { useRecached } from '@recached/vue'
const props = defineProps<{ userId: string }>()
const cache = useRecached()
const status = ref<string | null>(null)
watchEffect(() => {
status.value = cache.get(`user:${props.userId}:status`)
return cache.onMutation(() => {
status.value = cache.get(`user:${props.userId}:status`)
})
})
</script>For a fixed key, useKey is simpler and preferred.
useKeyJSON<T>(key)
function useKeyJSON<T>(key: string): Ref<T | null>Same as useKey but JSON-parses the stored string. Returns null when the key is missing, expired, or the stored value is not valid JSON.
Example
<script setup lang="ts">
import { useKeyJSON, useRecached } from '@recached/vue'
interface CartItem {
id: string
name: string
qty: number
price: number
}
const cache = useRecached()
const items = useKeyJSON<CartItem[]>('cart')
const total = computed(() =>
(items.value ?? []).reduce((sum, item) => sum + item.price * item.qty, 0)
)
function removeItem(id: string) {
cache.setJSON('cart', (items.value ?? []).filter((i) => i.id !== id))
}
</script>
<template>
<div>
<ul>
<li v-for="item in items ?? []" :key="item.id">
{{ item.name }} × {{ item.qty }}
<button @click="removeItem(item.id)">Remove</button>
</li>
</ul>
<p>Total: ${{ total.toFixed(2) }}</p>
</div>
</template>Writing JSON
Use cache.setJSON<T>() from useRecached() to write structured data:
cache.setJSON<CartItem[]>('cart', updatedItems) // no expiry
cache.setJSON<CartItem[]>('cart', updatedItems, 3600) // expires in 1 hourusePubSub(channel, handler)
function usePubSub(channel: string, handler: (msg: string) => void): voidSubscribe to a server pub/sub channel for the lifetime of the component. Sends SUBSCRIBE on setup and UNSUBSCRIBE on onUnmounted. The handler is called with each incoming message string.
Example
<script setup lang="ts">
import { ref } from 'vue'
import { usePubSub } from '@recached/vue'
const notifications = ref<string[]>([])
usePubSub('alerts', (msg) => {
notifications.value.push(msg)
})
</script>
<template>
<ul>
<li v-for="(n, i) in notifications" :key="i">{{ n }}</li>
</ul>
</template>Publishing
Use cache.publish() from useRecached() to send messages:
const cache = useRecached()
cache.publish('alerts', 'Deployment complete')All subscribers — Vue components, React components, server-side RESP clients — receive the message.
Reactivity model
Every mutation — regardless of source — fires the internal notification bus, which updates all useKey and useKeyJSON refs:
cache.set('key', value) ← local write
│
├─ WASM store updated
├─ notify all useKey('key') subscribers → Ref.value updated → Vue re-renders
├─ WebSocket send → server → fan-out to other clients
│ └─ WASM store updated → notify → Ref.value updated → Vue re-renders
└─ BroadcastChannel post → other tabs
└─ WASM store updated → notify → Ref.value updated → Vue re-rendersThe onMutation listener registered inside each composable is removed by onUnmounted, so components that unmount leave no dangling listeners.
TypeScript
All composables are fully typed. useKeyJSON<T> infers the generic from the type argument:
const user = useKeyJSON<User>('user:42') // Ref<User | null>
const tags = useKeyJSON<string[]>('tags') // Ref<string[] | null>useRecached() returns the full Cache type with all methods typed.