@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,203 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Provide/Inject Has Limited DevTools Support - Plan for Debugging
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Unlike props and state, provided values are harder to trace in Vue DevTools, making debugging more challenging
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, provide-inject, debugging, devtools, architecture]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Provide/Inject Has Limited DevTools Support - Plan for Debugging
|
|
10
|
+
|
|
11
|
+
**Impact: LOW** - While provide/inject is powerful for avoiding prop drilling, it creates less visible data flow than props. Provided values are not as easily inspectable in Vue DevTools, and tracing where a value comes from requires navigating the component tree manually.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Document provided values at the provider component level
|
|
16
|
+
- [ ] Use descriptive Symbol descriptions for easier identification
|
|
17
|
+
- [ ] Consider adding development-only logging for provided state changes
|
|
18
|
+
- [ ] Keep provide/inject chains shallow when possible
|
|
19
|
+
- [ ] Prefer Pinia for complex state that needs DevTools integration
|
|
20
|
+
|
|
21
|
+
## The Challenge
|
|
22
|
+
|
|
23
|
+
Unlike props which are clearly visible in Vue DevTools for each component, provided values:
|
|
24
|
+
|
|
25
|
+
1. Don't show which ancestor provided them
|
|
26
|
+
2. Require manual navigation to find the provider
|
|
27
|
+
3. Don't show in the standard props/data panels
|
|
28
|
+
4. Can be shadowed by closer ancestors using the same key
|
|
29
|
+
|
|
30
|
+
## Strategies for Better Debugging
|
|
31
|
+
|
|
32
|
+
### 1. Use Descriptive Symbol Names
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
// injection-keys.js
|
|
36
|
+
|
|
37
|
+
// BETTER: Descriptive names appear in errors and debugging
|
|
38
|
+
export const UserAuthKey = Symbol('UserAuthenticationState')
|
|
39
|
+
export const ThemeConfigKey = Symbol('ThemeConfiguration')
|
|
40
|
+
export const FormContextKey = Symbol('FormValidationContext')
|
|
41
|
+
|
|
42
|
+
// WORSE: Generic names are harder to trace
|
|
43
|
+
export const UserKey = Symbol()
|
|
44
|
+
export const ThemeKey = Symbol('theme')
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2. Document Providers Clearly
|
|
48
|
+
|
|
49
|
+
```vue
|
|
50
|
+
<!-- AuthProvider.vue -->
|
|
51
|
+
<script setup>
|
|
52
|
+
/**
|
|
53
|
+
* Authentication Provider
|
|
54
|
+
*
|
|
55
|
+
* Provides:
|
|
56
|
+
* - UserAuthKey: Current user state (Ref<User | null>)
|
|
57
|
+
* - AuthActionsKey: { login, logout, refresh }
|
|
58
|
+
*
|
|
59
|
+
* Must wrap any component that needs authentication state.
|
|
60
|
+
*/
|
|
61
|
+
import { provide, ref, readonly } from 'vue'
|
|
62
|
+
import { UserAuthKey, AuthActionsKey } from '@/injection-keys'
|
|
63
|
+
|
|
64
|
+
const user = ref(null)
|
|
65
|
+
|
|
66
|
+
// ... implementation
|
|
67
|
+
|
|
68
|
+
provide(UserAuthKey, readonly(user))
|
|
69
|
+
provide(AuthActionsKey, { login, logout, refresh })
|
|
70
|
+
</script>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 3. Development-Only Logging
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
// composables/useProvideWithLogging.js
|
|
77
|
+
import { provide, watch, getCurrentInstance } from 'vue'
|
|
78
|
+
|
|
79
|
+
export function useProvideWithLogging(key, value, name) {
|
|
80
|
+
provide(key, value)
|
|
81
|
+
|
|
82
|
+
if (import.meta.env.DEV) {
|
|
83
|
+
const instance = getCurrentInstance()
|
|
84
|
+
const componentName = instance?.type?.name || 'Unknown'
|
|
85
|
+
|
|
86
|
+
console.log(`[Provide] ${name} provided by <${componentName}>`)
|
|
87
|
+
|
|
88
|
+
// Log reactive changes
|
|
89
|
+
if (value && typeof value === 'object' && 'value' in value) {
|
|
90
|
+
watch(value, (newVal) => {
|
|
91
|
+
console.log(`[Provide] ${name} changed:`, newVal)
|
|
92
|
+
}, { deep: true })
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
```vue
|
|
99
|
+
<script setup>
|
|
100
|
+
import { ref } from 'vue'
|
|
101
|
+
import { useProvideWithLogging } from '@/composables/useProvideWithLogging'
|
|
102
|
+
import { ThemeKey } from '@/injection-keys'
|
|
103
|
+
|
|
104
|
+
const theme = ref('dark')
|
|
105
|
+
|
|
106
|
+
// In development, logs when provided and when changed
|
|
107
|
+
useProvideWithLogging(ThemeKey, theme, 'Theme')
|
|
108
|
+
</script>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 4. Inject with Missing Provider Warnings
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
// composables/useSafeInject.js
|
|
115
|
+
import { inject, getCurrentInstance } from 'vue'
|
|
116
|
+
|
|
117
|
+
export function useSafeInject(key, fallback, keyName) {
|
|
118
|
+
const value = inject(key, undefined)
|
|
119
|
+
|
|
120
|
+
if (value === undefined) {
|
|
121
|
+
const instance = getCurrentInstance()
|
|
122
|
+
const componentName = instance?.type?.name || 'Unknown'
|
|
123
|
+
|
|
124
|
+
if (import.meta.env.DEV) {
|
|
125
|
+
console.warn(
|
|
126
|
+
`[Inject] ${keyName || String(key)} not provided. ` +
|
|
127
|
+
`Component <${componentName}> is using fallback value. ` +
|
|
128
|
+
`Ensure a provider exists in the ancestor chain.`
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return typeof fallback === 'function' ? fallback() : fallback
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return value
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
```vue
|
|
140
|
+
<script setup>
|
|
141
|
+
import { useSafeInject } from '@/composables/useSafeInject'
|
|
142
|
+
import { ThemeKey } from '@/injection-keys'
|
|
143
|
+
|
|
144
|
+
// Warns in dev if no provider found
|
|
145
|
+
const theme = useSafeInject(ThemeKey, () => ({ mode: 'light' }), 'ThemeConfig')
|
|
146
|
+
</script>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 5. Create Provider Registry for Complex Apps
|
|
150
|
+
|
|
151
|
+
```js
|
|
152
|
+
// utils/provider-registry.js
|
|
153
|
+
const providerRegistry = new Map()
|
|
154
|
+
|
|
155
|
+
export function registerProvider(key, componentName, value) {
|
|
156
|
+
if (import.meta.env.DEV) {
|
|
157
|
+
providerRegistry.set(key, {
|
|
158
|
+
componentName,
|
|
159
|
+
value,
|
|
160
|
+
timestamp: Date.now()
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function getProviderInfo(key) {
|
|
166
|
+
return providerRegistry.get(key)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// For DevTools custom plugin or debugging
|
|
170
|
+
export function getAllProviders() {
|
|
171
|
+
return Object.fromEntries(providerRegistry)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Expose to window for console debugging
|
|
175
|
+
if (import.meta.env.DEV) {
|
|
176
|
+
window.__VUE_PROVIDERS__ = {
|
|
177
|
+
getAll: getAllProviders,
|
|
178
|
+
get: getProviderInfo
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## When to Use Pinia Instead
|
|
184
|
+
|
|
185
|
+
If you find yourself needing extensive debugging for state:
|
|
186
|
+
|
|
187
|
+
| Use Provide/Inject | Use Pinia |
|
|
188
|
+
|-------------------|-----------|
|
|
189
|
+
| Component library internals | Application-wide state |
|
|
190
|
+
| Theme/locale configuration | User session data |
|
|
191
|
+
| Form context | Shopping cart |
|
|
192
|
+
| Simple parent-child sharing | Complex state with actions |
|
|
193
|
+
| Plugin configuration | State that needs time-travel debugging |
|
|
194
|
+
|
|
195
|
+
Pinia provides excellent DevTools integration with:
|
|
196
|
+
- State inspection
|
|
197
|
+
- Time-travel debugging
|
|
198
|
+
- Action logging
|
|
199
|
+
- Hot module replacement
|
|
200
|
+
|
|
201
|
+
## Reference
|
|
202
|
+
- [Vue DevTools](https://devtools.vuejs.org/)
|
|
203
|
+
- [Pinia DevTools](https://pinia.vuejs.org/core-concepts/index.html#devtools)
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Factory Functions for Non-Primitive Inject Default Values
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Using object literals as default values creates shared references across all consuming components
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, provide-inject, composition-api, memory, shared-state]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Use Factory Functions for Non-Primitive Inject Default Values
|
|
10
|
+
|
|
11
|
+
**Impact: MEDIUM** - When providing default values for `inject()`, using an object literal creates a single shared reference. All components using that default will share the same object, leading to unexpected state sharing and bugs.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Always use factory functions for object/array default values in inject
|
|
16
|
+
- [ ] Pass `true` as the third argument to enable factory mode in Composition API
|
|
17
|
+
- [ ] Use the object syntax with factory function in Options API
|
|
18
|
+
- [ ] Only use literal defaults for primitive values (strings, numbers, booleans)
|
|
19
|
+
|
|
20
|
+
## The Gotcha: Shared Default References
|
|
21
|
+
|
|
22
|
+
**Wrong - Object literal creates shared reference:**
|
|
23
|
+
```vue
|
|
24
|
+
<script setup>
|
|
25
|
+
import { inject } from 'vue'
|
|
26
|
+
|
|
27
|
+
// WRONG: All components without a provider share this SAME object
|
|
28
|
+
const config = inject('config', { debug: false, apiUrl: '' })
|
|
29
|
+
|
|
30
|
+
// If one component does this:
|
|
31
|
+
config.debug = true
|
|
32
|
+
|
|
33
|
+
// ALL other components using this default now have debug: true!
|
|
34
|
+
</script>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Correct - Factory function creates unique instance:**
|
|
38
|
+
```vue
|
|
39
|
+
<script setup>
|
|
40
|
+
import { inject } from 'vue'
|
|
41
|
+
|
|
42
|
+
// CORRECT: Each component gets its own object
|
|
43
|
+
// Third argument `true` indicates the second arg is a factory function
|
|
44
|
+
const config = inject('config', () => ({ debug: false, apiUrl: '' }), true)
|
|
45
|
+
</script>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## API Explanation
|
|
49
|
+
|
|
50
|
+
The `inject()` function has multiple signatures:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
// Simple default value (OK for primitives)
|
|
54
|
+
inject(key, defaultValue)
|
|
55
|
+
|
|
56
|
+
// Factory function for non-primitives (REQUIRED for objects/arrays)
|
|
57
|
+
inject(key, factoryFunction, true)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The third argument `true` tells Vue that the second argument is a factory function, not the default value itself.
|
|
61
|
+
|
|
62
|
+
## Examples
|
|
63
|
+
|
|
64
|
+
### Primitive Defaults (No Factory Needed)
|
|
65
|
+
|
|
66
|
+
```vue
|
|
67
|
+
<script setup>
|
|
68
|
+
import { inject } from 'vue'
|
|
69
|
+
|
|
70
|
+
// Primitives are safe without factory
|
|
71
|
+
const count = inject('count', 0)
|
|
72
|
+
const name = inject('name', 'Guest')
|
|
73
|
+
const enabled = inject('enabled', false)
|
|
74
|
+
</script>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Object Defaults (Factory Required)
|
|
78
|
+
|
|
79
|
+
```vue
|
|
80
|
+
<script setup>
|
|
81
|
+
import { inject } from 'vue'
|
|
82
|
+
|
|
83
|
+
// Objects MUST use factory
|
|
84
|
+
const user = inject('user', () => ({
|
|
85
|
+
id: null,
|
|
86
|
+
name: 'Anonymous',
|
|
87
|
+
preferences: {}
|
|
88
|
+
}), true)
|
|
89
|
+
|
|
90
|
+
const settings = inject('settings', () => ({
|
|
91
|
+
theme: 'light',
|
|
92
|
+
language: 'en',
|
|
93
|
+
notifications: true
|
|
94
|
+
}), true)
|
|
95
|
+
</script>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Array Defaults (Factory Required)
|
|
99
|
+
|
|
100
|
+
```vue
|
|
101
|
+
<script setup>
|
|
102
|
+
import { inject } from 'vue'
|
|
103
|
+
|
|
104
|
+
// Arrays MUST use factory
|
|
105
|
+
const items = inject('items', () => [], true)
|
|
106
|
+
const permissions = inject('permissions', () => ['read'], true)
|
|
107
|
+
</script>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Class Instance Defaults (Factory Required)
|
|
111
|
+
|
|
112
|
+
```vue
|
|
113
|
+
<script setup>
|
|
114
|
+
import { inject } from 'vue'
|
|
115
|
+
import { Logger } from '@/utils/logger'
|
|
116
|
+
|
|
117
|
+
// Class instances MUST use factory
|
|
118
|
+
const logger = inject('logger', () => new Logger({ level: 'warn' }), true)
|
|
119
|
+
</script>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Options API Syntax
|
|
123
|
+
|
|
124
|
+
In Options API, use the object syntax with a `default` factory function:
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
export default {
|
|
128
|
+
inject: {
|
|
129
|
+
// Primitive - can use literal
|
|
130
|
+
theme: {
|
|
131
|
+
from: 'theme',
|
|
132
|
+
default: 'light'
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
// Object - MUST use factory
|
|
136
|
+
config: {
|
|
137
|
+
from: 'config',
|
|
138
|
+
default: () => ({ debug: false })
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
// Array - MUST use factory
|
|
142
|
+
permissions: {
|
|
143
|
+
from: 'permissions',
|
|
144
|
+
default: () => []
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Real-World Example: Form Context
|
|
151
|
+
|
|
152
|
+
```vue
|
|
153
|
+
<!-- FormProvider.vue -->
|
|
154
|
+
<script setup>
|
|
155
|
+
import { provide, reactive } from 'vue'
|
|
156
|
+
|
|
157
|
+
const formContext = reactive({
|
|
158
|
+
values: {},
|
|
159
|
+
errors: {},
|
|
160
|
+
touched: {},
|
|
161
|
+
isSubmitting: false
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
provide('formContext', formContext)
|
|
165
|
+
</script>
|
|
166
|
+
|
|
167
|
+
<!-- FormField.vue (might be used outside FormProvider) -->
|
|
168
|
+
<script setup>
|
|
169
|
+
import { inject } from 'vue'
|
|
170
|
+
|
|
171
|
+
// Safe default that won't be shared
|
|
172
|
+
const formContext = inject('formContext', () => ({
|
|
173
|
+
values: {},
|
|
174
|
+
errors: {},
|
|
175
|
+
touched: {},
|
|
176
|
+
isSubmitting: false,
|
|
177
|
+
// Mark as standalone mode
|
|
178
|
+
isStandalone: true
|
|
179
|
+
}), true)
|
|
180
|
+
|
|
181
|
+
// Component works both inside and outside FormProvider
|
|
182
|
+
</script>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## TypeScript: Typing Factory Defaults
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
import { inject } from 'vue'
|
|
189
|
+
import type { InjectionKey } from 'vue'
|
|
190
|
+
|
|
191
|
+
interface Config {
|
|
192
|
+
apiUrl: string
|
|
193
|
+
debug: boolean
|
|
194
|
+
features: string[]
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const ConfigKey: InjectionKey<Config> = Symbol('config')
|
|
198
|
+
|
|
199
|
+
// TypeScript understands the factory return type
|
|
200
|
+
const config = inject(ConfigKey, () => ({
|
|
201
|
+
apiUrl: 'https://api.example.com',
|
|
202
|
+
debug: false,
|
|
203
|
+
features: []
|
|
204
|
+
}), true)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Common Mistake in Testing
|
|
208
|
+
|
|
209
|
+
This gotcha often appears in tests where components are rendered without providers:
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
// test.spec.ts
|
|
213
|
+
import { mount } from '@vue/test-utils'
|
|
214
|
+
import MyComponent from './MyComponent.vue'
|
|
215
|
+
|
|
216
|
+
// Without provider, all test instances share the wrong default
|
|
217
|
+
it('test 1', () => {
|
|
218
|
+
const wrapper = mount(MyComponent)
|
|
219
|
+
wrapper.vm.config.debug = true // Pollutes other tests!
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
it('test 2', () => {
|
|
223
|
+
const wrapper = mount(MyComponent)
|
|
224
|
+
// Might fail because debug is still true from test 1
|
|
225
|
+
})
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Fix: Use factory functions in the component, or provide in tests:**
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
it('test with provider', () => {
|
|
232
|
+
const wrapper = mount(MyComponent, {
|
|
233
|
+
global: {
|
|
234
|
+
provide: {
|
|
235
|
+
config: { debug: false, apiUrl: '' }
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
})
|
|
239
|
+
})
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Reference
|
|
243
|
+
- [Vue.js inject() API Reference](https://vuejs.org/api/composition-api-dependency-injection.html#inject)
|
|
244
|
+
- [Vue.js Provide/Inject Guide](https://vuejs.org/guide/components/provide-inject.html)
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Provide/Inject Values Are Not Reactive by Default
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Provided primitive values lose reactivity, causing injecting components to not update when the source value changes
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, provide-inject, reactivity, composition-api, options-api]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Provide/Inject Values Are Not Reactive by Default
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - A common misconception is that provide/inject automatically maintains reactivity. By default, provided primitive values are NOT reactive. If the provided value changes in the provider, injecting components will NOT be updated.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Always wrap primitive values in `ref()` before providing
|
|
16
|
+
- [ ] Use `computed()` in Options API `provide()` for reactive data
|
|
17
|
+
- [ ] Never destructure refs when providing - pass the ref directly
|
|
18
|
+
- [ ] Understand that provided refs are NOT auto-unwrapped in injectors
|
|
19
|
+
|
|
20
|
+
## The Gotcha: Primitives Lose Reactivity
|
|
21
|
+
|
|
22
|
+
**Wrong - Primitive loses reactivity:**
|
|
23
|
+
```vue
|
|
24
|
+
<!-- Provider.vue -->
|
|
25
|
+
<script setup>
|
|
26
|
+
import { ref, provide } from 'vue'
|
|
27
|
+
|
|
28
|
+
const count = ref(0)
|
|
29
|
+
|
|
30
|
+
// WRONG: Providing the unwrapped value loses reactivity
|
|
31
|
+
provide('count', count.value) // Provides 0, not a reactive value
|
|
32
|
+
|
|
33
|
+
function increment() {
|
|
34
|
+
count.value++ // Injector will NOT see this change
|
|
35
|
+
}
|
|
36
|
+
</script>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```vue
|
|
40
|
+
<!-- Injector.vue -->
|
|
41
|
+
<script setup>
|
|
42
|
+
import { inject } from 'vue'
|
|
43
|
+
|
|
44
|
+
const count = inject('count') // Gets 0, forever static
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<template>
|
|
48
|
+
<!-- This will always show 0 -->
|
|
49
|
+
<div>Count: {{ count }}</div>
|
|
50
|
+
</template>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Correct - Provide the ref itself:**
|
|
54
|
+
```vue
|
|
55
|
+
<!-- Provider.vue -->
|
|
56
|
+
<script setup>
|
|
57
|
+
import { ref, provide } from 'vue'
|
|
58
|
+
|
|
59
|
+
const count = ref(0)
|
|
60
|
+
|
|
61
|
+
// CORRECT: Provide the ref, not the value
|
|
62
|
+
provide('count', count)
|
|
63
|
+
|
|
64
|
+
function increment() {
|
|
65
|
+
count.value++ // Injector WILL see this change
|
|
66
|
+
}
|
|
67
|
+
</script>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```vue
|
|
71
|
+
<!-- Injector.vue -->
|
|
72
|
+
<script setup>
|
|
73
|
+
import { inject } from 'vue'
|
|
74
|
+
|
|
75
|
+
// The ref is injected as-is, maintaining reactivity
|
|
76
|
+
const count = inject('count')
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<template>
|
|
80
|
+
<!-- Access .value in script, auto-unwrapped in template -->
|
|
81
|
+
<div>Count: {{ count }}</div>
|
|
82
|
+
</template>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Options API: Use computed() for Reactivity
|
|
86
|
+
|
|
87
|
+
In Options API, the `provide` option with plain properties is NOT reactive:
|
|
88
|
+
|
|
89
|
+
**Wrong - Options API without computed:**
|
|
90
|
+
```js
|
|
91
|
+
export default {
|
|
92
|
+
data() {
|
|
93
|
+
return {
|
|
94
|
+
message: 'Hello'
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
// WRONG: This is NOT reactive
|
|
98
|
+
provide() {
|
|
99
|
+
return {
|
|
100
|
+
message: this.message // Provides 'Hello' as a static string
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Correct - Use computed() in Options API:**
|
|
107
|
+
```js
|
|
108
|
+
import { computed } from 'vue'
|
|
109
|
+
|
|
110
|
+
export default {
|
|
111
|
+
data() {
|
|
112
|
+
return {
|
|
113
|
+
message: 'Hello'
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
provide() {
|
|
117
|
+
return {
|
|
118
|
+
// CORRECT: Wrap in computed for reactivity
|
|
119
|
+
message: computed(() => this.message)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Understanding Ref Behavior in Inject
|
|
126
|
+
|
|
127
|
+
When you provide a ref, it is injected as-is and NOT auto-unwrapped:
|
|
128
|
+
|
|
129
|
+
```vue
|
|
130
|
+
<!-- Provider.vue -->
|
|
131
|
+
<script setup>
|
|
132
|
+
import { ref, provide } from 'vue'
|
|
133
|
+
|
|
134
|
+
const user = ref({ name: 'John' })
|
|
135
|
+
provide('user', user)
|
|
136
|
+
</script>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
```vue
|
|
140
|
+
<!-- Injector.vue -->
|
|
141
|
+
<script setup>
|
|
142
|
+
import { inject } from 'vue'
|
|
143
|
+
|
|
144
|
+
const user = inject('user')
|
|
145
|
+
|
|
146
|
+
// In script, access with .value
|
|
147
|
+
console.log(user.value.name) // 'John'
|
|
148
|
+
|
|
149
|
+
function updateName(newName) {
|
|
150
|
+
user.value.name = newName // Works, but mutations should be in provider
|
|
151
|
+
}
|
|
152
|
+
</script>
|
|
153
|
+
|
|
154
|
+
<template>
|
|
155
|
+
<!-- In template, auto-unwrapped at top level -->
|
|
156
|
+
<div>{{ user.name }}</div>
|
|
157
|
+
</template>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Providing Reactive Objects
|
|
161
|
+
|
|
162
|
+
Reactive objects (created with `reactive()`) maintain reactivity when provided:
|
|
163
|
+
|
|
164
|
+
```vue
|
|
165
|
+
<!-- Provider.vue -->
|
|
166
|
+
<script setup>
|
|
167
|
+
import { reactive, provide } from 'vue'
|
|
168
|
+
|
|
169
|
+
const state = reactive({
|
|
170
|
+
count: 0,
|
|
171
|
+
message: 'Hello'
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
provide('state', state)
|
|
175
|
+
</script>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```vue
|
|
179
|
+
<!-- Injector.vue -->
|
|
180
|
+
<script setup>
|
|
181
|
+
import { inject } from 'vue'
|
|
182
|
+
|
|
183
|
+
const state = inject('state')
|
|
184
|
+
// state.count and state.message are reactive
|
|
185
|
+
</script>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Common Mistake: Destructuring Breaks Reactivity
|
|
189
|
+
|
|
190
|
+
**Wrong - Destructuring provided reactive state:**
|
|
191
|
+
```vue
|
|
192
|
+
<script setup>
|
|
193
|
+
import { inject } from 'vue'
|
|
194
|
+
|
|
195
|
+
// WRONG: Destructuring loses reactivity
|
|
196
|
+
const { count, message } = inject('state')
|
|
197
|
+
// count and message are now static values
|
|
198
|
+
</script>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Correct - Keep the reference intact:**
|
|
202
|
+
```vue
|
|
203
|
+
<script setup>
|
|
204
|
+
import { inject, toRefs } from 'vue'
|
|
205
|
+
|
|
206
|
+
const state = inject('state')
|
|
207
|
+
// Use state.count and state.message directly
|
|
208
|
+
|
|
209
|
+
// Or use toRefs if you need destructured reactive refs
|
|
210
|
+
const { count, message } = toRefs(state)
|
|
211
|
+
</script>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Debugging Tip
|
|
215
|
+
|
|
216
|
+
If your injected value isn't updating:
|
|
217
|
+
|
|
218
|
+
1. Check if you provided `ref.value` instead of `ref`
|
|
219
|
+
2. Check if you destructured a reactive object
|
|
220
|
+
3. In Options API, ensure you used `computed()`
|
|
221
|
+
4. Use Vue DevTools to inspect the provided values
|
|
222
|
+
|
|
223
|
+
## Reference
|
|
224
|
+
- [Vue.js Provide/Inject - Working with Reactivity](https://vuejs.org/guide/components/provide-inject.html#working-with-reactivity)
|
|
225
|
+
- [How to make provide/inject reactive - LogRocket Blog](https://blog.logrocket.com/how-to-make-provide-inject-reactive/)
|
|
226
|
+
- [GitHub Issue: Inject/Provide is not reactive](https://github.com/vuejs/vue/issues/7017)
|