Skip to content

Commit b095184

Browse files
committed
docs(createRegistry): clarify reactive: true footgun, recommend useProxyRegistry
1 parent 75af1bf commit b095184

File tree

2 files changed

+24
-1
lines changed

2 files changed

+24
-1
lines changed

apps/docs/src/pages/composables/reactivity/use-proxy-registry.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,29 @@ Vue's reactivity is granular. Components only re-render when they access propert
144144

145145
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.
146146

147+
??? Why not just use reactive: true on the registry?
148+
149+
`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.
150+
151+
`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.
152+
153+
```ts
154+
// Footgun: v-for may stop updating after a selection change
155+
const single = createSingle({ reactive: true })
156+
// After any selection-triggered re-render, addTab() won't update the list
157+
```
158+
159+
`useProxyRegistry` avoids this entirely — it updates via events, not dep tracking:
160+
161+
```ts
162+
// Safe: event-driven, no dep-tracking fragility
163+
const single = createSingle({ events: true })
164+
const proxy = useProxyRegistry(single)
165+
// proxy.values always reflects current state
166+
```
167+
168+
If 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.
169+
147170
??? Can I use useProxyRegistry with selection composables?
148171

149172
Yes. Selection composables extend `createRegistry`, so they work with `useProxyRegistry` if events are enabled:

apps/docs/src/pages/composables/registration/create-registry.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ Each branch extends the base ticket pattern with domain-specific capabilities. S
131131
| `dispose()` | Remove all tickets and clear event listeners |
132132

133133
> [!TIP] Need reactive collections?
134-
> Wrap with `useProxyRegistry(registry)` for full template reactivity, or pass `reactive: true` when creating the registry.
134+
> Use `useProxyRegistry(registry)` with `events: true` for reliable template reactivity. While `reactive: true` makes the internal collection a `shallowReactive` Map, `values()` caches its result — after any re-render not triggered by a collection mutation, Vue loses the reactive dependency on the collection, and future mutations won't trigger re-renders. See [useProxyRegistry](/composables/reactivity/use-proxy-registry) for details.
135135
136136
## Examples
137137

0 commit comments

Comments
 (0)