@pythoughts/vue-skills-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -0
- package/index.mjs +139 -0
- package/package.json +34 -0
- package/skills/create-adaptable-composable/SKILL.md +76 -0
- package/skills/vue-best-practices/SKILL.md +154 -0
- package/skills/vue-best-practices/references/animation-class-based-technique.md +254 -0
- package/skills/vue-best-practices/references/animation-state-driven-technique.md +291 -0
- package/skills/vue-best-practices/references/component-async.md +97 -0
- package/skills/vue-best-practices/references/component-data-flow.md +350 -0
- package/skills/vue-best-practices/references/component-fallthrough-attrs.md +174 -0
- package/skills/vue-best-practices/references/component-keep-alive.md +137 -0
- package/skills/vue-best-practices/references/component-slots.md +216 -0
- package/skills/vue-best-practices/references/component-suspense.md +228 -0
- package/skills/vue-best-practices/references/component-teleport.md +108 -0
- package/skills/vue-best-practices/references/component-transition-group.md +128 -0
- package/skills/vue-best-practices/references/component-transition.md +125 -0
- package/skills/vue-best-practices/references/composables.md +290 -0
- package/skills/vue-best-practices/references/directives.md +162 -0
- package/skills/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +159 -0
- package/skills/vue-best-practices/references/perf-v-once-v-memo-directives.md +182 -0
- package/skills/vue-best-practices/references/perf-virtualize-large-lists.md +187 -0
- package/skills/vue-best-practices/references/plugins.md +166 -0
- package/skills/vue-best-practices/references/reactivity.md +346 -0
- package/skills/vue-best-practices/references/render-functions.md +201 -0
- package/skills/vue-best-practices/references/sfc.md +310 -0
- package/skills/vue-best-practices/references/state-management.md +135 -0
- package/skills/vue-best-practices/references/updated-hook-performance.md +187 -0
- package/skills/vue-debug-guides/SKILL.md +205 -0
- package/skills/vue-debug-guides/reference/animation-key-for-rerender.md +160 -0
- package/skills/vue-debug-guides/reference/animation-transitiongroup-performance.md +241 -0
- package/skills/vue-debug-guides/reference/async-component-error-handling.md +115 -0
- package/skills/vue-debug-guides/reference/async-component-keepalive-ref-issue.md +112 -0
- package/skills/vue-debug-guides/reference/async-component-suspense-control.md +84 -0
- package/skills/vue-debug-guides/reference/async-component-vue-router.md +109 -0
- package/skills/vue-debug-guides/reference/attrs-event-listener-merging.md +205 -0
- package/skills/vue-debug-guides/reference/checkbox-true-false-value-form-submission.md +118 -0
- package/skills/vue-debug-guides/reference/cleanup-side-effects.md +172 -0
- package/skills/vue-debug-guides/reference/click-events-on-components.md +180 -0
- package/skills/vue-debug-guides/reference/component-naming-conflicts.md +159 -0
- package/skills/vue-debug-guides/reference/component-ref-requires-defineexpose.md +176 -0
- package/skills/vue-debug-guides/reference/composable-avoid-hidden-side-effects.md +208 -0
- package/skills/vue-debug-guides/reference/composable-call-location-restrictions.md +141 -0
- package/skills/vue-debug-guides/reference/composable-naming-return-pattern.md +139 -0
- package/skills/vue-debug-guides/reference/composable-tovalue-inside-watcheffect.md +182 -0
- package/skills/vue-debug-guides/reference/composition-api-not-functional-programming.md +120 -0
- package/skills/vue-debug-guides/reference/composition-api-script-setup-async-context.md +203 -0
- package/skills/vue-debug-guides/reference/composition-api-vs-react-hooks-differences.md +156 -0
- package/skills/vue-debug-guides/reference/computed-array-mutation.md +148 -0
- package/skills/vue-debug-guides/reference/computed-conditional-dependencies.md +147 -0
- package/skills/vue-debug-guides/reference/computed-no-parameters.md +159 -0
- package/skills/vue-debug-guides/reference/computed-no-side-effects.md +107 -0
- package/skills/vue-debug-guides/reference/computed-return-value-readonly.md +160 -0
- package/skills/vue-debug-guides/reference/configure-app-before-mount.md +89 -0
- package/skills/vue-debug-guides/reference/declare-emits-for-documentation.md +212 -0
- package/skills/vue-debug-guides/reference/define-expose-before-await.md +192 -0
- package/skills/vue-debug-guides/reference/define-model-default-value-sync.md +139 -0
- package/skills/vue-debug-guides/reference/defineEmits-must-be-top-level.md +164 -0
- package/skills/vue-debug-guides/reference/defineEmits-no-runtime-and-type-mixed.md +170 -0
- package/skills/vue-debug-guides/reference/definemodel-object-mutation-no-emit.md +148 -0
- package/skills/vue-debug-guides/reference/dom-update-timing-nexttick.md +90 -0
- package/skills/vue-debug-guides/reference/dynamic-argument-constraints.md +146 -0
- package/skills/vue-debug-guides/reference/dynamic-component-registration-vite.md +147 -0
- package/skills/vue-debug-guides/reference/event-modifier-order-matters.md +101 -0
- package/skills/vue-debug-guides/reference/exact-modifier-for-precise-shortcuts.md +155 -0
- package/skills/vue-debug-guides/reference/fallthrough-attrs-overwrite-vue3.md +159 -0
- package/skills/vue-debug-guides/reference/in-dom-template-parsing-caveats.md +149 -0
- package/skills/vue-debug-guides/reference/inheritattrs-false-for-wrapper-components.md +230 -0
- package/skills/vue-debug-guides/reference/keepalive-router-nested-double-mount.md +222 -0
- package/skills/vue-debug-guides/reference/keepalive-transition-memory-leak.md +144 -0
- package/skills/vue-debug-guides/reference/keyup-modifier-timing.md +137 -0
- package/skills/vue-debug-guides/reference/lifecycle-dom-access-timing.md +216 -0
- package/skills/vue-debug-guides/reference/lifecycle-hooks-synchronous-registration.md +156 -0
- package/skills/vue-debug-guides/reference/lifecycle-ssr-awareness.md +184 -0
- package/skills/vue-debug-guides/reference/local-components-not-in-descendants.md +151 -0
- package/skills/vue-debug-guides/reference/mount-return-value.md +88 -0
- package/skills/vue-debug-guides/reference/multi-root-component-class-attrs.md +93 -0
- package/skills/vue-debug-guides/reference/native-event-collision-with-emits.md +162 -0
- package/skills/vue-debug-guides/reference/no-passive-with-prevent.md +141 -0
- package/skills/vue-debug-guides/reference/no-v-if-with-v-for.md +136 -0
- package/skills/vue-debug-guides/reference/perf-computed-object-stability.md +157 -0
- package/skills/vue-debug-guides/reference/perf-props-stability-update-optimization.md +140 -0
- package/skills/vue-debug-guides/reference/plugin-global-properties-sparingly.md +109 -0
- package/skills/vue-debug-guides/reference/plugin-install-before-mount.md +124 -0
- package/skills/vue-debug-guides/reference/plugin-prefer-provide-inject-over-global-properties.md +120 -0
- package/skills/vue-debug-guides/reference/plugin-typescript-type-augmentation.md +157 -0
- package/skills/vue-debug-guides/reference/prop-defineprops-scope-limitation.md +161 -0
- package/skills/vue-debug-guides/reference/provide-inject-debugging-challenges.md +203 -0
- package/skills/vue-debug-guides/reference/provide-inject-default-value-factory.md +244 -0
- package/skills/vue-debug-guides/reference/provide-inject-reactivity-not-automatic.md +226 -0
- package/skills/vue-debug-guides/reference/provide-inject-synchronous-setup.md +235 -0
- package/skills/vue-debug-guides/reference/reactive-destructuring.md +89 -0
- package/skills/vue-debug-guides/reference/reactivity-debugging-hooks.md +132 -0
- package/skills/vue-debug-guides/reference/reactivity-markraw-for-non-reactive.md +149 -0
- package/skills/vue-debug-guides/reference/reactivity-proxy-identity-hazard.md +96 -0
- package/skills/vue-debug-guides/reference/reactivity-same-tick-batching.md +166 -0
- package/skills/vue-debug-guides/reference/ref-value-access.md +61 -0
- package/skills/vue-debug-guides/reference/refs-in-collections-need-value.md +81 -0
- package/skills/vue-debug-guides/reference/render-function-avoid-internal-vnode-properties.md +151 -0
- package/skills/vue-debug-guides/reference/render-function-vnodes-must-be-unique.md +133 -0
- package/skills/vue-debug-guides/reference/rendering-render-function-h-import-vue3.md +148 -0
- package/skills/vue-debug-guides/reference/rendering-render-function-return-from-setup.md +148 -0
- package/skills/vue-debug-guides/reference/rendering-render-function-slots-as-functions.md +168 -0
- package/skills/vue-debug-guides/reference/rendering-resolve-component-for-string-names.md +231 -0
- package/skills/vue-debug-guides/reference/select-initial-value-ios-bug.md +91 -0
- package/skills/vue-debug-guides/reference/self-referencing-component-name.md +157 -0
- package/skills/vue-debug-guides/reference/sfc-named-exports-forbidden.md +184 -0
- package/skills/vue-debug-guides/reference/sfc-scoped-css-child-component-styling.md +156 -0
- package/skills/vue-debug-guides/reference/sfc-scoped-css-dynamic-content.md +193 -0
- package/skills/vue-debug-guides/reference/sfc-scoped-css-slot-content.md +242 -0
- package/skills/vue-debug-guides/reference/sfc-script-setup-reactivity.md +195 -0
- package/skills/vue-debug-guides/reference/slot-forwarding-to-child-components.md +143 -0
- package/skills/vue-debug-guides/reference/slot-implicit-default-content.md +155 -0
- package/skills/vue-debug-guides/reference/slot-name-reserved-prop.md +109 -0
- package/skills/vue-debug-guides/reference/slot-named-scoped-explicit-default.md +95 -0
- package/skills/vue-debug-guides/reference/slot-render-scope-parent-only.md +135 -0
- package/skills/vue-debug-guides/reference/slot-v-slot-on-components-or-templates-only.md +122 -0
- package/skills/vue-debug-guides/reference/ssr-hydration-mismatch-causes.md +280 -0
- package/skills/vue-debug-guides/reference/ssr-platform-specific-apis.md +256 -0
- package/skills/vue-debug-guides/reference/state-ssr-cross-request-pollution.md +276 -0
- package/skills/vue-debug-guides/reference/suspense-no-builtin-error-handling.md +127 -0
- package/skills/vue-debug-guides/reference/suspense-ssr-hydration-issues.md +159 -0
- package/skills/vue-debug-guides/reference/tailwind-dynamic-class-generation.md +144 -0
- package/skills/vue-debug-guides/reference/teleport-scoped-styles-limitation.md +191 -0
- package/skills/vue-debug-guides/reference/teleport-ssr-hydration.md +152 -0
- package/skills/vue-debug-guides/reference/teleport-target-must-exist.md +113 -0
- package/skills/vue-debug-guides/reference/template-expressions-restrictions.md +114 -0
- package/skills/vue-debug-guides/reference/template-functions-no-side-effects.md +187 -0
- package/skills/vue-debug-guides/reference/template-ref-null-with-v-if.md +123 -0
- package/skills/vue-debug-guides/reference/template-ref-unwrapping-top-level.md +104 -0
- package/skills/vue-debug-guides/reference/template-ref-v-for-order.md +172 -0
- package/skills/vue-debug-guides/reference/textarea-no-interpolation.md +72 -0
- package/skills/vue-debug-guides/reference/transition-group-flip-inline-elements.md +152 -0
- package/skills/vue-debug-guides/reference/transition-group-move-animation-position-absolute.md +130 -0
- package/skills/vue-debug-guides/reference/transition-group-no-default-wrapper-vue3.md +152 -0
- package/skills/vue-debug-guides/reference/transition-js-hooks-done-callback.md +251 -0
- package/skills/vue-debug-guides/reference/transition-nested-duration.md +182 -0
- package/skills/vue-debug-guides/reference/transition-reusable-scoped-style.md +245 -0
- package/skills/vue-debug-guides/reference/transition-router-view-appear.md +193 -0
- package/skills/vue-debug-guides/reference/transition-type-when-mixed.md +172 -0
- package/skills/vue-debug-guides/reference/transition-unmount-hook-timing.md +149 -0
- package/skills/vue-debug-guides/reference/ts-defineprops-boolean-default-false.md +225 -0
- package/skills/vue-debug-guides/reference/ts-defineprops-imported-types-limitations.md +281 -0
- package/skills/vue-debug-guides/reference/ts-event-handler-explicit-typing.md +213 -0
- package/skills/vue-debug-guides/reference/ts-reactive-no-generic-argument.md +196 -0
- package/skills/vue-debug-guides/reference/ts-shallowref-for-dynamic-components.md +218 -0
- package/skills/vue-debug-guides/reference/ts-template-ref-null-handling.md +249 -0
- package/skills/vue-debug-guides/reference/ts-template-type-casting.md +214 -0
- package/skills/vue-debug-guides/reference/ts-withdefaults-mutable-factory-function.md +171 -0
- package/skills/vue-debug-guides/reference/undeclared-emits-double-firing.md +195 -0
- package/skills/vue-debug-guides/reference/use-template-ref-vue35.md +158 -0
- package/skills/vue-debug-guides/reference/v-else-must-follow-v-if.md +136 -0
- package/skills/vue-debug-guides/reference/v-for-component-props.md +95 -0
- package/skills/vue-debug-guides/reference/v-for-computed-reverse-sort.md +86 -0
- package/skills/vue-debug-guides/reference/v-for-key-attribute.md +90 -0
- package/skills/vue-debug-guides/reference/v-for-range-starts-at-one.md +66 -0
- package/skills/vue-debug-guides/reference/v-if-null-check-order.md +171 -0
- package/skills/vue-debug-guides/reference/v-model-ignores-html-attributes.md +83 -0
- package/skills/vue-debug-guides/reference/v-model-ime-composition.md +83 -0
- package/skills/vue-debug-guides/reference/v-model-number-modifier-behavior.md +124 -0
- package/skills/vue-debug-guides/reference/v-show-template-limitation.md +124 -0
- package/skills/vue-debug-guides/reference/watch-async-cleanup.md +180 -0
- package/skills/vue-debug-guides/reference/watch-async-creation-memory-leak.md +176 -0
- package/skills/vue-debug-guides/reference/watch-deep-same-object-reference.md +165 -0
- package/skills/vue-debug-guides/reference/watch-flush-timing.md +189 -0
- package/skills/vue-debug-guides/reference/watch-reactive-property-getter.md +108 -0
- package/skills/vue-debug-guides/reference/watcheffect-async-dependency-tracking.md +173 -0
- package/skills/vue-debug-guides/reference/watcheffect-flush-post-for-refs.md +176 -0
- package/skills/vue-jsx-best-practices/SKILL.md +12 -0
- package/skills/vue-jsx-best-practices/reference/render-function-jsx-vue-vs-react.md +141 -0
- package/skills/vue-options-api-best-practices/SKILL.md +23 -0
- package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-lifecycle-hooks.md +95 -0
- package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-methods.md +68 -0
- package/skills/vue-options-api-best-practices/reference/stateful-methods-lifecycle.md +61 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-arrow-functions-validators.md +141 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-computed-return-types.md +192 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-proptype-complex-types.md +212 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-provide-inject-limitations.md +135 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-type-event-handlers.md +202 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-use-definecomponent.md +172 -0
- package/skills/vue-options-api-best-practices/reference/ts-strict-mode-options-api.md +197 -0
- package/skills/vue-pinia-best-practices/SKILL.md +21 -0
- package/skills/vue-pinia-best-practices/reference/pinia-no-active-pinia-error.md +248 -0
- package/skills/vue-pinia-best-practices/reference/pinia-setup-store-return-all-state.md +227 -0
- package/skills/vue-pinia-best-practices/reference/pinia-store-destructuring-breaks-reactivity.md +193 -0
- package/skills/vue-pinia-best-practices/reference/state-url-for-ephemeral-filters.md +238 -0
- package/skills/vue-pinia-best-practices/reference/state-use-pinia-for-large-apps.md +262 -0
- package/skills/vue-pinia-best-practices/reference/store-method-binding-parentheses.md +191 -0
- package/skills/vue-router-best-practices/SKILL.md +23 -0
- package/skills/vue-router-best-practices/reference/router-beforeenter-no-param-trigger.md +167 -0
- package/skills/vue-router-best-practices/reference/router-beforerouteenter-no-this.md +176 -0
- package/skills/vue-router-best-practices/reference/router-guard-async-await-pattern.md +227 -0
- package/skills/vue-router-best-practices/reference/router-navigation-guard-infinite-loop.md +187 -0
- package/skills/vue-router-best-practices/reference/router-navigation-guard-next-deprecated.md +150 -0
- package/skills/vue-router-best-practices/reference/router-param-change-no-lifecycle.md +181 -0
- package/skills/vue-router-best-practices/reference/router-simple-routing-cleanup.md +209 -0
- package/skills/vue-router-best-practices/reference/router-use-vue-router-for-production.md +183 -0
- package/skills/vue-testing-best-practices/SKILL.md +29 -0
- package/skills/vue-testing-best-practices/reference/async-component-testing.md +163 -0
- package/skills/vue-testing-best-practices/reference/teleport-testing-complexity.md +158 -0
- package/skills/vue-testing-best-practices/reference/testing-async-await-flushpromises.md +175 -0
- package/skills/vue-testing-best-practices/reference/testing-browser-vs-node-runners.md +208 -0
- package/skills/vue-testing-best-practices/reference/testing-component-blackbox-approach.md +144 -0
- package/skills/vue-testing-best-practices/reference/testing-composables-helper-wrapper.md +238 -0
- package/skills/vue-testing-best-practices/reference/testing-e2e-playwright-recommended.md +242 -0
- package/skills/vue-testing-best-practices/reference/testing-no-snapshot-only.md +197 -0
- package/skills/vue-testing-best-practices/reference/testing-pinia-store-setup.md +228 -0
- package/skills/vue-testing-best-practices/reference/testing-suspense-async-components.md +229 -0
- package/skills/vue-testing-best-practices/reference/testing-vitest-recommended-for-vue.md +204 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use flush post for watchEffect with Template Refs
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Default watchEffect runs before DOM updates, causing refs to be out of sync
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, watchEffect, template-refs, flush, dom-timing]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Use flush post for watchEffect with Template Refs
|
|
10
|
+
|
|
11
|
+
**Impact: MEDIUM** - By default, `watchEffect` runs before the DOM is updated. When watching template refs, this means the effect may run with stale or null ref values. Use `flush: 'post'` to ensure the effect runs after DOM updates when refs are current.
|
|
12
|
+
|
|
13
|
+
This timing issue is particularly confusing because the watcher runs, but the ref doesn't yet reflect the current DOM state.
|
|
14
|
+
|
|
15
|
+
## Task Checklist
|
|
16
|
+
|
|
17
|
+
- [ ] Use `{ flush: 'post' }` when watchEffect accesses template refs
|
|
18
|
+
- [ ] Alternatively, use `watchPostEffect` helper for cleaner syntax
|
|
19
|
+
- [ ] Still include null checks as refs can be unmounted
|
|
20
|
+
- [ ] Consider using `watch` with explicit ref watching instead
|
|
21
|
+
|
|
22
|
+
**Incorrect:**
|
|
23
|
+
```vue
|
|
24
|
+
<script setup>
|
|
25
|
+
import { ref, watchEffect } from 'vue'
|
|
26
|
+
|
|
27
|
+
const inputEl = ref(null)
|
|
28
|
+
const text = ref('')
|
|
29
|
+
|
|
30
|
+
// WRONG: Runs BEFORE DOM update - ref may be null or stale
|
|
31
|
+
watchEffect(() => {
|
|
32
|
+
// On first run: inputEl.value is null (DOM not rendered yet)
|
|
33
|
+
// On updates: May reference old element state
|
|
34
|
+
if (inputEl.value) {
|
|
35
|
+
console.log('Input value:', inputEl.value.value) // Stale!
|
|
36
|
+
inputEl.value.focus()
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<template>
|
|
42
|
+
<input ref="inputEl" v-model="text" />
|
|
43
|
+
</template>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```vue
|
|
47
|
+
<script setup>
|
|
48
|
+
import { ref, watchEffect } from 'vue'
|
|
49
|
+
|
|
50
|
+
const items = ref([1, 2, 3])
|
|
51
|
+
const itemRefs = ref([])
|
|
52
|
+
|
|
53
|
+
// WRONG: Refs array not yet populated when this runs
|
|
54
|
+
watchEffect(() => {
|
|
55
|
+
console.log('Number of refs:', itemRefs.value.length) // Always 0!
|
|
56
|
+
})
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<template>
|
|
60
|
+
<div v-for="item in items" :key="item" :ref="el => itemRefs.value.push(el)">
|
|
61
|
+
{{ item }}
|
|
62
|
+
</div>
|
|
63
|
+
</template>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Correct:**
|
|
67
|
+
```vue
|
|
68
|
+
<script setup>
|
|
69
|
+
import { ref, watchEffect } from 'vue'
|
|
70
|
+
|
|
71
|
+
const inputEl = ref(null)
|
|
72
|
+
const text = ref('')
|
|
73
|
+
|
|
74
|
+
// CORRECT: flush: 'post' runs AFTER DOM update
|
|
75
|
+
watchEffect(() => {
|
|
76
|
+
if (inputEl.value) {
|
|
77
|
+
console.log('Input value:', inputEl.value.value) // Current!
|
|
78
|
+
inputEl.value.focus()
|
|
79
|
+
}
|
|
80
|
+
}, { flush: 'post' })
|
|
81
|
+
</script>
|
|
82
|
+
|
|
83
|
+
<template>
|
|
84
|
+
<input ref="inputEl" v-model="text" />
|
|
85
|
+
</template>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```vue
|
|
89
|
+
<script setup>
|
|
90
|
+
import { ref, watchPostEffect } from 'vue'
|
|
91
|
+
|
|
92
|
+
const inputEl = ref(null)
|
|
93
|
+
const showInput = ref(true)
|
|
94
|
+
|
|
95
|
+
// CORRECT: watchPostEffect is shorthand for flush: 'post'
|
|
96
|
+
watchPostEffect(() => {
|
|
97
|
+
if (inputEl.value) {
|
|
98
|
+
inputEl.value.focus()
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
</script>
|
|
102
|
+
|
|
103
|
+
<template>
|
|
104
|
+
<input v-if="showInput" ref="inputEl" />
|
|
105
|
+
</template>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```vue
|
|
109
|
+
<script setup>
|
|
110
|
+
import { ref, watch, onMounted } from 'vue'
|
|
111
|
+
|
|
112
|
+
const inputEl = ref(null)
|
|
113
|
+
|
|
114
|
+
// ALTERNATIVE: Use watch on the ref directly
|
|
115
|
+
watch(inputEl, (el) => {
|
|
116
|
+
if (el) {
|
|
117
|
+
el.focus()
|
|
118
|
+
}
|
|
119
|
+
}, { flush: 'post' })
|
|
120
|
+
|
|
121
|
+
// ALTERNATIVE: For one-time setup, onMounted is sufficient
|
|
122
|
+
onMounted(() => {
|
|
123
|
+
inputEl.value?.focus()
|
|
124
|
+
})
|
|
125
|
+
</script>
|
|
126
|
+
|
|
127
|
+
<template>
|
|
128
|
+
<input ref="inputEl" />
|
|
129
|
+
</template>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
```vue
|
|
133
|
+
<script setup>
|
|
134
|
+
import { useTemplateRef, watchPostEffect } from 'vue'
|
|
135
|
+
|
|
136
|
+
// Vue 3.5+ with useTemplateRef
|
|
137
|
+
const input = useTemplateRef('my-input')
|
|
138
|
+
|
|
139
|
+
// CORRECT: watchPostEffect with useTemplateRef
|
|
140
|
+
watchPostEffect(() => {
|
|
141
|
+
input.value?.focus()
|
|
142
|
+
})
|
|
143
|
+
</script>
|
|
144
|
+
|
|
145
|
+
<template>
|
|
146
|
+
<input ref="my-input" />
|
|
147
|
+
</template>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Flush Options Explained
|
|
151
|
+
|
|
152
|
+
```javascript
|
|
153
|
+
// Default: 'pre' - runs before DOM update
|
|
154
|
+
watchEffect(() => { ... }) // Same as { flush: 'pre' }
|
|
155
|
+
|
|
156
|
+
// 'post' - runs after DOM update (use for refs)
|
|
157
|
+
watchEffect(() => { ... }, { flush: 'post' })
|
|
158
|
+
watchPostEffect(() => { ... }) // Shorthand
|
|
159
|
+
|
|
160
|
+
// 'sync' - runs synchronously (rarely needed, can cause issues)
|
|
161
|
+
watchEffect(() => { ... }, { flush: 'sync' })
|
|
162
|
+
watchSyncEffect(() => { ... }) // Shorthand
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## When to Use Each Flush Mode
|
|
166
|
+
|
|
167
|
+
| Scenario | Recommended Flush |
|
|
168
|
+
|----------|-------------------|
|
|
169
|
+
| Accessing template refs | `post` |
|
|
170
|
+
| Reading updated DOM | `post` |
|
|
171
|
+
| Triggering before render | `pre` (default) |
|
|
172
|
+
| Performance-critical sync updates | `sync` (with caution) |
|
|
173
|
+
|
|
174
|
+
## Reference
|
|
175
|
+
- [Vue.js Watchers - Callback Flush Timing](https://vuejs.org/guide/essentials/watchers.html#callback-flush-timing)
|
|
176
|
+
- [Vue.js watchEffect API](https://vuejs.org/api/reactivity-core.html#watcheffect)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vue-jsx-best-practices
|
|
3
|
+
description: JSX syntax in Vue (e.g., class vs className, JSX plugin config).
|
|
4
|
+
version: 2.0.0
|
|
5
|
+
license: MIT
|
|
6
|
+
author: github.com/Pythoughts-labs
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Vue JSX best practices and differences from React JSX.
|
|
10
|
+
|
|
11
|
+
### JSX
|
|
12
|
+
- Migrating React JSX code to Vue or getting attribute type errors → See [render-function-jsx-vue-vs-react](reference/render-function-jsx-vue-vs-react.md)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Vue JSX Uses HTML Attributes Not React Conventions
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Using className or htmlFor in Vue JSX causes TypeScript errors and inconsistent code style
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, jsx, tsx, render-function]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Vue JSX Uses HTML Attributes Not React Conventions
|
|
10
|
+
|
|
11
|
+
**Impact: MEDIUM** - Vue's JSX transform uses standard HTML attribute names (`class`, `for`) instead of React's JavaScript-friendly names (`className`, `htmlFor`). With proper TypeScript configuration, using React conventions like `className` or `htmlFor` will produce TypeScript errors, which is good for catching these inconsistencies early. Note that Vue's runtime is lenient and will actually convert these attributes correctly, but using HTML attributes is the recommended practice for consistency with Vue templates and proper type safety.
|
|
12
|
+
|
|
13
|
+
When writing JSX in Vue, use the same attribute names you would use in regular HTML templates. This is a fundamental difference from React's JSX where `class` and `for` are reserved JavaScript keywords.
|
|
14
|
+
|
|
15
|
+
## Task Checklist
|
|
16
|
+
|
|
17
|
+
- [ ] Use `class` instead of `className` in Vue JSX
|
|
18
|
+
- [ ] Use `for` instead of `htmlFor` in Vue JSX
|
|
19
|
+
- [ ] Use standard HTML event names with `on` prefix (onClick, onInput)
|
|
20
|
+
- [ ] When migrating React components to Vue, update all attribute names
|
|
21
|
+
- [ ] Configure TypeScript properly for Vue JSX type inference
|
|
22
|
+
|
|
23
|
+
**Incorrect (React-style):**
|
|
24
|
+
```jsx
|
|
25
|
+
// AVOID: React conventions cause TypeScript errors in Vue JSX
|
|
26
|
+
// (Vue runtime is lenient and converts these, but types don't allow them)
|
|
27
|
+
export default {
|
|
28
|
+
setup() {
|
|
29
|
+
return () => (
|
|
30
|
+
<div className="container">
|
|
31
|
+
<label htmlFor="email">Email:</label>
|
|
32
|
+
<input id="email" className="input-field" />
|
|
33
|
+
</div>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
// AVOID: TypeScript will reject className/htmlFor with Vue's JSX types
|
|
41
|
+
const Button = () => (
|
|
42
|
+
<button
|
|
43
|
+
className="btn btn-primary" // TS error: Property 'className' does not exist
|
|
44
|
+
htmlFor="form" // TS error: Property 'htmlFor' does not exist
|
|
45
|
+
>
|
|
46
|
+
Submit
|
|
47
|
+
</button>
|
|
48
|
+
)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Correct (Vue-style):**
|
|
52
|
+
```jsx
|
|
53
|
+
// CORRECT: Use standard HTML attributes
|
|
54
|
+
export default {
|
|
55
|
+
setup() {
|
|
56
|
+
return () => (
|
|
57
|
+
<div class="container">
|
|
58
|
+
<label for="email">Email:</label>
|
|
59
|
+
<input id="email" class="input-field" />
|
|
60
|
+
</div>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
// CORRECT: Vue TSX with HTML attributes
|
|
68
|
+
const Button = () => (
|
|
69
|
+
<button
|
|
70
|
+
class="btn btn-primary"
|
|
71
|
+
>
|
|
72
|
+
Submit
|
|
73
|
+
</button>
|
|
74
|
+
)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## TypeScript Configuration for Vue JSX
|
|
78
|
+
|
|
79
|
+
To enable proper type inference and IntelliSense for Vue JSX/TSX, configure your `tsconfig.json`:
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"compilerOptions": {
|
|
84
|
+
"jsx": "preserve",
|
|
85
|
+
"jsxImportSource": "vue"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Starting from Vue 3.4, Vue no longer implicitly registers the global JSX namespace, so `jsxImportSource` is required for TypeScript to use Vue's JSX type definitions.
|
|
91
|
+
|
|
92
|
+
## Vite Configuration
|
|
93
|
+
|
|
94
|
+
For Vite projects, ensure you have the JSX plugin configured in `vite.config.ts`:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { defineConfig } from 'vite'
|
|
98
|
+
import vue from '@vitejs/plugin-vue'
|
|
99
|
+
import vueJsx from '@vitejs/plugin-vue-jsx'
|
|
100
|
+
|
|
101
|
+
export default defineConfig({
|
|
102
|
+
plugins: [vue(), vueJsx()]
|
|
103
|
+
})
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Other Attribute Differences
|
|
107
|
+
|
|
108
|
+
| React JSX | Vue JSX | HTML |
|
|
109
|
+
|-----------|---------|------|
|
|
110
|
+
| className | class | class |
|
|
111
|
+
| htmlFor | for | for |
|
|
112
|
+
| onChange | onInput (for live updates) | oninput |
|
|
113
|
+
| tabIndex | tabindex | tabindex |
|
|
114
|
+
| readOnly | readonly | readonly |
|
|
115
|
+
|
|
116
|
+
## Event Handling in Vue JSX
|
|
117
|
+
|
|
118
|
+
```jsx
|
|
119
|
+
// Vue JSX event handling
|
|
120
|
+
export default {
|
|
121
|
+
setup() {
|
|
122
|
+
const handleClick = () => console.log('clicked')
|
|
123
|
+
const handleInput = (e) => console.log(e.target.value)
|
|
124
|
+
|
|
125
|
+
return () => (
|
|
126
|
+
<div>
|
|
127
|
+
<button onClick={handleClick}>Click</button>
|
|
128
|
+
<input onInput={handleInput} />
|
|
129
|
+
|
|
130
|
+
{/* Event modifiers via helper */}
|
|
131
|
+
<div onClick={withModifiers(handleClick, ['self'])}>
|
|
132
|
+
Only triggers on self
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Reference
|
|
141
|
+
- [Vue.js JSX and TSX](https://vuejs.org/guide/extras/render-function.html#jsx-tsx)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vue-options-api-best-practices
|
|
3
|
+
description: "Vue 3 Options API style (data(), methods, this context). Each reference shows Options API solution only."
|
|
4
|
+
version: 2.0.0
|
|
5
|
+
license: MIT
|
|
6
|
+
author: github.com/Pythoughts-labs
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Vue.js Options API best practices, TypeScript integration, and common gotchas.
|
|
10
|
+
|
|
11
|
+
### TypeScript
|
|
12
|
+
- Need to enable TypeScript type inference for component properties → See [ts-options-api-use-definecomponent](reference/ts-options-api-use-definecomponent.md)
|
|
13
|
+
- Enabling type safety for Options API this context → See [ts-strict-mode-options-api](reference/ts-strict-mode-options-api.md)
|
|
14
|
+
- Using old TypeScript versions with prop validators → See [ts-options-api-arrow-functions-validators](reference/ts-options-api-arrow-functions-validators.md)
|
|
15
|
+
- Event handler parameters need proper type safety → See [ts-options-api-type-event-handlers](reference/ts-options-api-type-event-handlers.md)
|
|
16
|
+
- Need to type object or array props with interfaces → See [ts-options-api-proptype-complex-types](reference/ts-options-api-proptype-complex-types.md)
|
|
17
|
+
- Injected properties missing TypeScript types completely → See [ts-options-api-provide-inject-limitations](reference/ts-options-api-provide-inject-limitations.md)
|
|
18
|
+
- Complex computed properties lack clear type documentation → See [ts-options-api-computed-return-types](reference/ts-options-api-computed-return-types.md)
|
|
19
|
+
|
|
20
|
+
### Methods & Lifecycle
|
|
21
|
+
- Methods aren't binding to component instance context → See [no-arrow-functions-in-methods](reference/no-arrow-functions-in-methods.md)
|
|
22
|
+
- Lifecycle hooks losing access to component data → See [no-arrow-functions-in-lifecycle-hooks](reference/no-arrow-functions-in-lifecycle-hooks.md)
|
|
23
|
+
- Debounced functions sharing state across component instances → See [stateful-methods-lifecycle](reference/stateful-methods-lifecycle.md)
|
package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-lifecycle-hooks.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Never Use Arrow Functions for Options API Lifecycle Hooks
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Arrow functions in lifecycle hooks break `this` binding to component instance
|
|
5
|
+
type: capability
|
|
6
|
+
tags: [vue3, vue2, options-api, lifecycle, arrow-functions, this-binding, mounted, created]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Never Use Arrow Functions for Options API Lifecycle Hooks
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - Using arrow functions for lifecycle hooks in the Options API prevents Vue from binding `this` to the component instance. This causes `this` to be `undefined` or reference the wrong context, leading to runtime errors when accessing component data, methods, or other properties.
|
|
12
|
+
|
|
13
|
+
Arrow functions lexically bind `this` from their enclosing scope. Vue's Options API lifecycle hooks (created, mounted, updated, unmounted, etc.) require regular functions so Vue can set `this` to the component instance at runtime.
|
|
14
|
+
|
|
15
|
+
## Task Checklist
|
|
16
|
+
|
|
17
|
+
- [ ] Always use regular function syntax for Options API lifecycle hooks
|
|
18
|
+
- [ ] Use ES6 method shorthand (preferred) for cleaner code
|
|
19
|
+
- [ ] Arrow functions ARE allowed inside lifecycle hooks for callbacks
|
|
20
|
+
|
|
21
|
+
**Incorrect:**
|
|
22
|
+
```javascript
|
|
23
|
+
export default {
|
|
24
|
+
data() {
|
|
25
|
+
return { message: 'Hello' }
|
|
26
|
+
},
|
|
27
|
+
// WRONG: Arrow function - `this` will be undefined
|
|
28
|
+
created: () => {
|
|
29
|
+
console.log(this.message) // Error: Cannot read property 'message' of undefined
|
|
30
|
+
},
|
|
31
|
+
// WRONG: Arrow function for mounted
|
|
32
|
+
mounted: () => {
|
|
33
|
+
this.initializePlugin() // Error: this.initializePlugin is not a function
|
|
34
|
+
},
|
|
35
|
+
// WRONG: Arrow function for beforeUnmount
|
|
36
|
+
beforeUnmount: () => {
|
|
37
|
+
this.cleanup() // Will fail!
|
|
38
|
+
},
|
|
39
|
+
methods: {
|
|
40
|
+
initializePlugin() { /* ... */ },
|
|
41
|
+
cleanup() { /* ... */ }
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Correct:**
|
|
47
|
+
```javascript
|
|
48
|
+
export default {
|
|
49
|
+
data() {
|
|
50
|
+
return { message: 'Hello' }
|
|
51
|
+
},
|
|
52
|
+
// CORRECT: ES6 method shorthand (preferred)
|
|
53
|
+
created() {
|
|
54
|
+
console.log(this.message) // Works! this refers to component instance
|
|
55
|
+
},
|
|
56
|
+
// CORRECT: Regular function expression
|
|
57
|
+
mounted: function() {
|
|
58
|
+
this.initializePlugin() // Works!
|
|
59
|
+
},
|
|
60
|
+
// CORRECT: Method shorthand
|
|
61
|
+
beforeUnmount() {
|
|
62
|
+
this.cleanup() // Works!
|
|
63
|
+
},
|
|
64
|
+
methods: {
|
|
65
|
+
initializePlugin() {
|
|
66
|
+
// Arrow functions ARE fine for callbacks inside lifecycle hooks
|
|
67
|
+
this.$nextTick(() => {
|
|
68
|
+
this.isReady = true // Arrow inherits `this` from mounted
|
|
69
|
+
})
|
|
70
|
+
},
|
|
71
|
+
cleanup() { /* ... */ }
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## All Affected Lifecycle Hooks
|
|
77
|
+
|
|
78
|
+
The following Options API hooks must NOT use arrow functions:
|
|
79
|
+
- `beforeCreate`
|
|
80
|
+
- `created`
|
|
81
|
+
- `beforeMount`
|
|
82
|
+
- `mounted`
|
|
83
|
+
- `beforeUpdate`
|
|
84
|
+
- `updated`
|
|
85
|
+
- `beforeUnmount` (Vue 3) / `beforeDestroy` (Vue 2)
|
|
86
|
+
- `unmounted` (Vue 3) / `destroyed` (Vue 2)
|
|
87
|
+
- `activated`
|
|
88
|
+
- `deactivated`
|
|
89
|
+
- `errorCaptured`
|
|
90
|
+
- `renderTracked`
|
|
91
|
+
- `renderTriggered`
|
|
92
|
+
|
|
93
|
+
## Reference
|
|
94
|
+
- [Vue.js Lifecycle Hooks](https://vuejs.org/guide/essentials/lifecycle.html)
|
|
95
|
+
- [Vue.js Options Lifecycle](https://vuejs.org/api/options-lifecycle.html)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Never Use Arrow Functions in Methods Option
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Arrow functions prevent Vue from binding `this` to the component instance
|
|
5
|
+
type: capability
|
|
6
|
+
tags: [vue3, vue2, options-api, methods, this-binding]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Never Use Arrow Functions in Methods Option
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - Using arrow functions in the `methods` option causes `this` to be `undefined` or the wrong context, leading to runtime errors when trying to access component data, computed properties, or other methods.
|
|
12
|
+
|
|
13
|
+
Arrow functions lexically bind `this` from their enclosing scope, not from the object they're defined on. Vue's `methods` option requires regular functions so Vue can bind `this` to the component instance.
|
|
14
|
+
|
|
15
|
+
## Task Checklist
|
|
16
|
+
|
|
17
|
+
- [ ] Always use regular function syntax for methods in Options API
|
|
18
|
+
- [ ] If using ES6 shorthand, use method shorthand (preferred)
|
|
19
|
+
- [ ] Arrow functions ARE allowed inside methods for callbacks
|
|
20
|
+
|
|
21
|
+
**Incorrect:**
|
|
22
|
+
```javascript
|
|
23
|
+
export default {
|
|
24
|
+
data() {
|
|
25
|
+
return { count: 0 }
|
|
26
|
+
},
|
|
27
|
+
methods: {
|
|
28
|
+
// WRONG: Arrow function - `this` will be undefined
|
|
29
|
+
increment: () => {
|
|
30
|
+
this.count++ // Error: Cannot read property 'count' of undefined
|
|
31
|
+
},
|
|
32
|
+
// WRONG: Arrow function assigned to property
|
|
33
|
+
decrement: () => {
|
|
34
|
+
this.count--
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Correct:**
|
|
41
|
+
```javascript
|
|
42
|
+
export default {
|
|
43
|
+
data() {
|
|
44
|
+
return { count: 0 }
|
|
45
|
+
},
|
|
46
|
+
methods: {
|
|
47
|
+
// CORRECT: ES6 method shorthand (preferred)
|
|
48
|
+
increment() {
|
|
49
|
+
this.count++ // Works! this refers to component instance
|
|
50
|
+
},
|
|
51
|
+
// CORRECT: Traditional function expression
|
|
52
|
+
decrement: function() {
|
|
53
|
+
this.count--
|
|
54
|
+
},
|
|
55
|
+
// Arrow functions ARE fine for callbacks INSIDE methods
|
|
56
|
+
fetchData() {
|
|
57
|
+
fetch('/api/data')
|
|
58
|
+
.then(response => response.json())
|
|
59
|
+
.then(data => {
|
|
60
|
+
this.data = data // Arrow function inherits `this` from fetchData
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Reference
|
|
68
|
+
- [Vue.js Methods - Avoid Arrow Functions](https://vuejs.org/guide/essentials/reactivity-fundamentals.html#methods)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Create Stateful Methods in Lifecycle Hooks
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Stateful functions like debounce/throttle in methods are shared across all component instances
|
|
5
|
+
type: capability
|
|
6
|
+
tags: [vue3, options-api, debounce, throttle, lifecycle, cleanup]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Create Stateful Methods in Lifecycle Hooks
|
|
10
|
+
|
|
11
|
+
**Impact: MEDIUM** - If you define debounced, throttled, or other stateful functions directly in the `methods` option, all instances of the component share the same function state. This causes race conditions and bugs in lists of components.
|
|
12
|
+
|
|
13
|
+
When a component is reused (e.g., in v-for), each instance needs its own debounced/throttled function. Define these in the `created()` hook and clean them up in `unmounted()` to prevent memory leaks.
|
|
14
|
+
|
|
15
|
+
## Task Checklist
|
|
16
|
+
|
|
17
|
+
- [ ] Never define debounced/throttled functions directly in `methods`
|
|
18
|
+
- [ ] Create stateful functions in `created()` lifecycle hook
|
|
19
|
+
- [ ] Always clean up (cancel timers) in `unmounted()`
|
|
20
|
+
|
|
21
|
+
**Incorrect:**
|
|
22
|
+
```javascript
|
|
23
|
+
import { debounce } from 'lodash-es'
|
|
24
|
+
|
|
25
|
+
export default {
|
|
26
|
+
methods: {
|
|
27
|
+
// WRONG: All component instances share this debounced function!
|
|
28
|
+
// If used in a v-for, clicking one button affects all instances
|
|
29
|
+
handleClick: debounce(function() {
|
|
30
|
+
this.performSearch()
|
|
31
|
+
}, 500)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Correct:**
|
|
37
|
+
```javascript
|
|
38
|
+
import { debounce } from 'lodash-es'
|
|
39
|
+
|
|
40
|
+
export default {
|
|
41
|
+
created() {
|
|
42
|
+
// CORRECT: Each instance gets its own debounced function
|
|
43
|
+
this.debouncedSearch = debounce(this.performSearch, 500)
|
|
44
|
+
},
|
|
45
|
+
unmounted() {
|
|
46
|
+
// CORRECT: Clean up to prevent memory leaks and stale calls
|
|
47
|
+
this.debouncedSearch.cancel()
|
|
48
|
+
},
|
|
49
|
+
methods: {
|
|
50
|
+
handleClick() {
|
|
51
|
+
this.debouncedSearch()
|
|
52
|
+
},
|
|
53
|
+
performSearch() {
|
|
54
|
+
// Actual search logic
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Reference
|
|
61
|
+
- [Vue.js Reactivity Fundamentals - Stateful Methods](https://vuejs.org/guide/essentials/reactivity-fundamentals.html#stateful-methods)
|