Add nuxt-skills and update auto quotes to use new policy API structure
- Add nuxt-skills (vue, nuxt, nuxt-ui) to .claude/skills/ - Create useCustomerSelection() composable for managing insured/buyer selection - Create usePolicyApi() composable for policy API operations - Update auto quote components to use insured/buyer instead of client - Update vehicle fields: remove valorVehiculo, add market_value, requested_value, rc_limits - Make chassis_number and engine_number optional - Update auto quote types and composables to match new API structure - Update auto quote page to submit to policy API with new structure
This commit is contained in:
289
.claude/skills/vue/references/reactivity.md
Normal file
289
.claude/skills/vue/references/reactivity.md
Normal file
@@ -0,0 +1,289 @@
|
||||
---
|
||||
name: Vue Reactivity System
|
||||
description: Core reactivity primitives - ref, reactive, computed, and watchers
|
||||
---
|
||||
|
||||
# Vue Reactivity System
|
||||
|
||||
Vue's reactivity system enables automatic tracking of state changes and DOM updates.
|
||||
|
||||
## ref()
|
||||
|
||||
Create reactive primitive values with `ref()`. Access/modify via `.value` in JavaScript, auto-unwrapped in templates.
|
||||
|
||||
```ts
|
||||
import { ref } from 'vue'
|
||||
|
||||
const count = ref(0)
|
||||
console.log(count.value) // 0
|
||||
count.value++
|
||||
```
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
const count = ref(0)
|
||||
|
||||
function increment() {
|
||||
count.value++
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button @click="increment">{{ count }}</button>
|
||||
</template>
|
||||
```
|
||||
|
||||
### Typing refs
|
||||
|
||||
```ts
|
||||
import { ref } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
// Type inference
|
||||
const year = ref(2020) // Ref<number>
|
||||
|
||||
// Explicit generic
|
||||
const name = ref<string | null>(null)
|
||||
|
||||
// Ref type annotation
|
||||
const id: Ref<string | number> = ref('abc')
|
||||
```
|
||||
|
||||
## reactive()
|
||||
|
||||
Create reactive objects. No `.value` needed, but cannot reassign the entire object.
|
||||
|
||||
```ts
|
||||
import { reactive } from 'vue'
|
||||
|
||||
interface State {
|
||||
count: number
|
||||
name: string
|
||||
}
|
||||
|
||||
const state: State = reactive({
|
||||
count: 0,
|
||||
name: 'Vue'
|
||||
})
|
||||
|
||||
state.count++ // reactive
|
||||
```
|
||||
|
||||
### Limitations of reactive()
|
||||
|
||||
1. **Only works with objects** - not primitives
|
||||
2. **Cannot replace entire object** - loses reactivity
|
||||
3. **Destructuring loses reactivity** - use `toRefs()` instead
|
||||
|
||||
```ts
|
||||
const state = reactive({ count: 0 })
|
||||
|
||||
// ❌ Loses reactivity
|
||||
let { count } = state
|
||||
|
||||
// ✅ Use toRefs
|
||||
import { toRefs } from 'vue'
|
||||
const { count } = toRefs(state)
|
||||
```
|
||||
|
||||
## Recommendation
|
||||
|
||||
Use `ref()` as the primary API for declaring reactive state - it works with any value type and has consistent behavior.
|
||||
|
||||
## Deep Reactivity
|
||||
|
||||
Both `ref()` and `reactive()` are deeply reactive by default:
|
||||
|
||||
```ts
|
||||
const obj = ref({
|
||||
nested: { count: 0 },
|
||||
arr: ['foo', 'bar']
|
||||
})
|
||||
|
||||
// These trigger updates
|
||||
obj.value.nested.count++
|
||||
obj.value.arr.push('baz')
|
||||
```
|
||||
|
||||
Use `shallowRef()` or `shallowReactive()` to opt out of deep reactivity for performance.
|
||||
|
||||
## DOM Update Timing
|
||||
|
||||
DOM updates are batched and asynchronous. Use `nextTick()` to wait for updates:
|
||||
|
||||
```ts
|
||||
import { ref, nextTick } from 'vue'
|
||||
|
||||
const count = ref(0)
|
||||
|
||||
async function increment() {
|
||||
count.value++
|
||||
await nextTick()
|
||||
// DOM is now updated
|
||||
}
|
||||
```
|
||||
|
||||
## Ref Unwrapping Rules
|
||||
|
||||
- **In templates**: Top-level refs auto-unwrap
|
||||
- **In reactive objects**: Refs auto-unwrap when accessed as properties
|
||||
- **In arrays/collections**: Refs do NOT auto-unwrap
|
||||
|
||||
```ts
|
||||
const count = ref(0)
|
||||
const state = reactive({ count })
|
||||
|
||||
console.log(state.count) // 0 (unwrapped)
|
||||
|
||||
const books = reactive([ref('Vue Guide')])
|
||||
console.log(books[0].value) // Need .value
|
||||
```
|
||||
|
||||
## computed()
|
||||
|
||||
Derive values from reactive state with automatic caching. Only re-evaluates when dependencies change.
|
||||
|
||||
```ts
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
const firstName = ref('John')
|
||||
const lastName = ref('Doe')
|
||||
|
||||
// Readonly computed
|
||||
const fullName = computed(() => `${firstName.value} ${lastName.value}`)
|
||||
|
||||
// Writable computed
|
||||
const fullNameWritable = computed({
|
||||
get() {
|
||||
return `${firstName.value} ${lastName.value}`
|
||||
},
|
||||
set(newValue: string) {
|
||||
[firstName.value, lastName.value] = newValue.split(' ')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Computed Best Practices
|
||||
|
||||
- **Getters should be pure** - no side effects, no mutating other state
|
||||
- **Don't mutate computed values** - mutate the source instead
|
||||
- **Use computed over methods** for derived data (caching benefit)
|
||||
|
||||
```ts
|
||||
// ✅ Cached - only recalculates when items changes
|
||||
const activeItems = computed(() => items.value.filter(x => x.active))
|
||||
|
||||
// ❌ Not cached - runs on every render
|
||||
function getActiveItems() {
|
||||
return items.value.filter(x => x.active)
|
||||
}
|
||||
```
|
||||
|
||||
## watch()
|
||||
|
||||
Explicitly watch reactive sources and run side effects when they change. Lazy by default.
|
||||
|
||||
```ts
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
const id = ref(1)
|
||||
|
||||
watch(id, async (newId, oldId) => {
|
||||
const data = await fetchData(newId)
|
||||
// handle data...
|
||||
})
|
||||
```
|
||||
|
||||
### Watch Source Types
|
||||
|
||||
```ts
|
||||
const x = ref(0)
|
||||
const obj = reactive({ count: 0 })
|
||||
|
||||
// Single ref
|
||||
watch(x, (newX) => console.log(newX))
|
||||
|
||||
// Getter function
|
||||
watch(() => obj.count, (count) => console.log(count))
|
||||
|
||||
// Multiple sources
|
||||
watch([x, () => obj.count], ([newX, newCount]) => {
|
||||
console.log(newX, newCount)
|
||||
})
|
||||
```
|
||||
|
||||
### Watch Options
|
||||
|
||||
```ts
|
||||
watch(source, callback, {
|
||||
immediate: true, // Run immediately on creation
|
||||
deep: true, // Watch nested properties
|
||||
once: true, // Trigger only once (3.4+)
|
||||
flush: 'post' // Run after DOM update
|
||||
})
|
||||
```
|
||||
|
||||
## watchEffect()
|
||||
|
||||
Automatically tracks dependencies and runs immediately. Re-runs when any tracked dependency changes.
|
||||
|
||||
```ts
|
||||
import { ref, watchEffect } from 'vue'
|
||||
|
||||
const todoId = ref(1)
|
||||
const data = ref(null)
|
||||
|
||||
watchEffect(async () => {
|
||||
const response = await fetch(`/api/todos/${todoId.value}`)
|
||||
data.value = await response.json()
|
||||
})
|
||||
```
|
||||
|
||||
### watch vs watchEffect
|
||||
|
||||
| Feature | watch | watchEffect |
|
||||
| ------------------- | ---------------- | --------------------- |
|
||||
| Dependency tracking | Explicit | Automatic |
|
||||
| Lazy | Yes | No (immediate) |
|
||||
| Access old value | Yes | No |
|
||||
| Best for | Specific sources | Multiple dependencies |
|
||||
|
||||
## Watcher Cleanup (3.5+)
|
||||
|
||||
Cancel stale async operations:
|
||||
|
||||
```ts
|
||||
import { watch, onWatcherCleanup } from 'vue'
|
||||
|
||||
watch(id, async (newId) => {
|
||||
const controller = new AbortController()
|
||||
|
||||
fetch(`/api/${newId}`, { signal: controller.signal })
|
||||
|
||||
onWatcherCleanup(() => controller.abort())
|
||||
})
|
||||
```
|
||||
|
||||
## Stopping Watchers
|
||||
|
||||
```ts
|
||||
const stop = watch(source, callback)
|
||||
const stop2 = watchEffect(() => { /* ... */ })
|
||||
|
||||
// Stop manually
|
||||
stop()
|
||||
stop2()
|
||||
|
||||
// Pause/Resume (3.5+)
|
||||
const { stop, pause, resume } = watchEffect(() => { /* ... */ })
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vuejs.org/guide/essentials/reactivity-fundamentals.html
|
||||
- https://vuejs.org/guide/essentials/computed.html
|
||||
- https://vuejs.org/guide/essentials/watchers.html
|
||||
- https://vuejs.org/api/reactivity-core.html
|
||||
-->
|
||||
Reference in New Issue
Block a user