useProxyRegistry
A reactive proxy wrapper for registry collections that automatically updates refs when items are registered or unregistered.
Usage
The useProxyRegistry composable creates reactive objects that automatically sync with a registry’s state. It listens for registry changes and updates the reactive properties accordingly, making it ideal for template-driven UIs that need to react to registry mutations.
Important: The registry must have events: true enabled for the proxy to receive updates.
import { createRegistry, useProxyRegistry } from '@vuetify/v0'
const registry = createRegistry({ events: true })
const proxy = useProxyRegistry(registry)
registry.register({ value: 'Item 1' })
registry.register({ value: 'Item 2' })
console.log(proxy.size) // 2
console.log(proxy.keys) // [id1, id2]Architecture
useProxyRegistry creates a reactive proxy over registry collections:
Reactivity
useProxyRegistry returns a fully reactive object that syncs with registry events. Use it to expose registry data in Vue templates.
| Property | Reactive | Notes |
|---|---|---|
keys | Updates on register/unregister | |
values | Updates on register/unregister/update | |
entries | Updates on any ticket change | |
size | Updates on register/unregister |
Deep vs shallow Pass { deep: true } for reactive(), or omit for shallowReactive() (default). Shallow is more performant when ticket internals don’t need tracking.
Frequently Asked Questions
useProxyRegistry listens for register and unregister events to know when to update reactive properties. Without events, the registry operates silently:
// Without events - proxy never updates
const registry = createRegistry()
const proxy = useProxyRegistry(registry)
registry.register({ value: 'item' })
console.log(proxy.size) // 0 - stale!
// With events - proxy stays in sync
const registry = createRegistry({ events: true })
const proxy = useProxyRegistry(registry)
registry.register({ value: 'item' })
console.log(proxy.size) // 1 - correctEvents add minimal overhead but aren’t enabled by default since many use cases don’t need reactivity. See createRegistry for the full events API.
Two costs to consider:
| Operation | Raw Registry | With Proxy |
|---|---|---|
register/unregister | O(1) | O(1) + event emit + ref update |
| Property access | Direct Map/Set | Ref unwrap (negligible) |
The proxy adds one event listener and updates refs on mutations. For most apps, this is insignificant. If you’re registering thousands of items per second, benchmark your specific case.
All read properties from the underlying registry:
| Property | Type | Reactive |
|---|---|---|
size | number | Yes |
keys | ID[] | Yes |
values | unknown[] | Yes |
items | Map<ID, Ticket> | Yes |
has(id) | boolean | Yes |
get(id) | Ticket | undefined | Yes |
Mutations (register, unregister, move) are called on the underlying registry instance — not through the proxy. The proxy automatically syncs via registry events.
Vue’s reactivity is granular. Components only re-render when they access properties that changed:
<template>
<!-- Only re-renders when size changes -->
<span>{{ proxy.size }} items</span>
</template><template>
<!-- Re-renders when any item changes -->
<div v-for="id in proxy.keys" :key="id">
{{ proxy.get(id)?.value }}
</div>
</template>If you only read size, adding items triggers a re-render. If you iterate keys, any registration change triggers a re-render. Structure templates to minimize reactive dependencies.
reactive: true makes the internal collection a shallowReactive(new Map()), which looks like it should drive a v-for reactively — but there’s a subtle footgun.
values() caches its result internally and only invalidates when the collection mutates. Vue’s render effect clears all reactive dependencies on every run, then re-establishes them as reactive sources are read. If a re-render is triggered by something other than a collection mutation (e.g., a selection change), values() returns from cache without reading the underlying Map — so Vue never re-establishes the dep. The next time you add an item, Vue doesn’t know to re-render.
// Footgun: v-for may stop updating after a selection change
const single = createSingle({ reactive: true })
// After any selection-triggered re-render, addTab() won't update the listuseProxyRegistry avoids this entirely — it updates via events, not dep tracking:
// Safe: event-driven, no dep-tracking fragility
const single = createSingle({ events: true })
const proxy = useProxyRegistry(single)
// proxy.values always reflects current stateIf you need reactive: true for ticket-level prop tracking, you can bypass the cache by reading single.collection.values() directly in the template — but useProxyRegistry is the recommended approach.
Yes. Selection composables extend createRegistry, so they work with useProxyRegistry if events are enabled:
import { createSelection, useProxyRegistry } from '@vuetify/v0'
const selection = createSelection({ events: true, multiple: true })
const proxy = useProxyRegistry(selection)
// Reactive access to registered items
proxy.size // Updates when items register/unregister
// Selection-specific state is still on the original
selection.selectedIds // Set of selected IDsThe proxy only exposes registry properties. For reactive selection state, use the selection instance directly or create a custom reactive wrapper.
Examples
Notification Center
A registry-based notification queue using useProxyRegistry to make the item list reactively drive the template without manual event subscriptions.
Build succeeded
success · #0
Disk usage at 85%
warning · #1
New user signed up
info · #2
Functions
useProxyRegistry
(registry: RegistryContext<Z, E>, options?: ProxyRegistryOptions | undefined) => ProxyRegistryContext<E>Creates a proxy registry that provides reactive objects for registry data.
Options
deep
boolean | undefinedProperties
Benchmarks
Every operation is profiled across multiple dataset sizes to measure real-world throughput. Each benchmark is assigned a performance tier—good, fast, blazing, or slow—and groups are scored by averaging their individual results so you can spot bottlenecks at a glance. This transparency helps you make informed decisions about which patterns scale for your use case. Learn more in the benchmarks guide.