← Back to Vera
AgentVera

Skill · Version 1.0.0

Predictable Vue state updates

Organizes reactive state so the interface updates when expected, without duplicated values, looping watchers or abandoned background work.

vue-reactivity

See how it helps

When is it useful?

Use when a Vue view stops updating, recalculates too often or triggers repeated requests after a small change.

What does it help you do?

  • Chooses appropriate reactive containers and keeps one authoritative owner for each value.
  • Calculates derived values directly instead of synchronizing duplicate state through watchers.
  • Limits watchers to real side effects and cleans up timers, listeners and pending work.

Try asking this

Fix a filter panel whose totals become stale and whose watchers trigger repeated requests. Derive totals from one source and clean up requests when filters change. Change two filters quickly and reset them together. Totals must derive from the latest state, with one intended request sequence and no watcher feedback loop.

Detailed documentation

Read the skill’s original instructions, examples and checks in their authored language.

Details…Show less

Vue Reactivity & Composition API

Drive the UI from a clear, minimal reactive state graph: one authoritative source per state, pure computed derivations, and explicit side-effect watchers with cleanup.

1. Choosing reactive primitives

  • Default to ref() for primitives, arrays and objects whose whole value may be replaced. Use .value in <script> and rely on top-level unwrapping in <template>.
  • Use shallowRef() (or shallowReactive()) for large datasets, third-party instances (charts, editors, map SDKs) or immutable server payloads where deep tracking adds needless overhead. Trigger updates by replacing .value or calling triggerRef().
  • If you use reactive(), never reassign the variable (state = ... severs the reference) and never destructure its properties directly (const { count } = state loses reactivity); use toRef() or toRefs().
  • Refs inside reactive({}) unwrap automatically, but refs inside plain arrays (reactive([ref(1)])), Map/Set, or nested non-top-level template expressions still require .value or a computed.

2. Derived state with computed

  • Derive every value that is a function of existing state with computed() instead of storing a duplicate ref synchronized in a watch.
  • Keep computed getters pure and synchronous: no network calls, no DOM mutations, no mutating other state, and no in-place array mutations (list.value.sort() or .reverse() mutates the source — copy first with [...list.value].sort() or .toSorted()).

3. Watchers and side effects

  • Use watch or watchEffect only for real side effects (fetching data, syncing DOM/storage, imperative third-party APIs), never to cascade state between local refs.
  • Choose the right watcher:
    • watch(source, cb): explicit dependencies, lazy by default, provides (newVal, oldVal). Pass a getter () => props.id when watching a reactive property; passing props.id directly passes a raw value and fails to track.
    • watchEffect(cb): runs immediately and tracks every reactive property read synchronously before the first await.
  • Avoid deep: true on large objects when a targeted getter () => [form.status, form.assigneeId] suffices.
  • Clean up async or subscribed side effects when the source changes or the scope disposes: use onWatcherCleanup(fn) (Vue 3.5+, called synchronously before await) or the onCleanup parameter in watch((_, __, onCleanup) => ...).
  • Use watchPostEffect (flush: 'post') when the callback reads Vue-updated DOM geometry.

4. Lifecycle and resource cleanup

  • Call lifecycle hooks (onMounted, onUpdated, onUnmounted, onScopeDispose) synchronously inside <script setup> or setup(), never after an await.
  • Pair every addEventListener, ResizeObserver, IntersectionObserver, timer (setInterval, setTimeout), WebSocket or store subscription with cleanup in onUnmounted / onScopeDispose.

Before you finish

  • Every state has one primary owner; derived values use pure computed(), not synced refs.
  • No lost reactivity from destructuring reactive() or passing raw property values to watch().
  • Watchers perform side effects only, avoid chained loops, and cancel stale work on re-run.
  • Every listener, timer, observer and subscription is cleaned up on unmount or scope disposal.

Included files 2

  • LICENSE.txt
  • SKILL.md