@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,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Import h Globally in Vue 3 Render Functions
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Vue 3 requires explicit h import; using Vue 2 patterns causes runtime errors
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, render-function, migration, h, vnode, breaking-change]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Import h Globally in Vue 3 Render Functions
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - In Vue 2, the `h` function (createElement) was passed as an argument to render functions. In Vue 3, `h` must be explicitly imported from 'vue'. Using Vue 2 patterns causes runtime errors.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Import `h` from 'vue' at the top of files using render functions
|
|
16
|
+
- [ ] Remove the `h` parameter from render function signatures
|
|
17
|
+
- [ ] Update all render functions when migrating from Vue 2
|
|
18
|
+
|
|
19
|
+
**Incorrect (Vue 2 pattern - broken in Vue 3):**
|
|
20
|
+
```js
|
|
21
|
+
// WRONG: Vue 2 pattern - h is not passed as argument in Vue 3
|
|
22
|
+
export default {
|
|
23
|
+
render(h) { // h is undefined in Vue 3!
|
|
24
|
+
return h('div', [
|
|
25
|
+
h('span', 'Hello')
|
|
26
|
+
])
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// WRONG: Using createElement alias from Vue 2
|
|
31
|
+
export default {
|
|
32
|
+
render(createElement) { // Also undefined
|
|
33
|
+
return createElement('div', 'Hello')
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Correct (Vue 3 pattern):**
|
|
39
|
+
```js
|
|
40
|
+
// CORRECT: Import h from vue
|
|
41
|
+
import { h } from 'vue'
|
|
42
|
+
|
|
43
|
+
export default {
|
|
44
|
+
render() {
|
|
45
|
+
return h('div', [
|
|
46
|
+
h('span', 'Hello')
|
|
47
|
+
])
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## With Composition API
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
import { h, ref } from 'vue'
|
|
56
|
+
|
|
57
|
+
export default {
|
|
58
|
+
setup() {
|
|
59
|
+
const count = ref(0)
|
|
60
|
+
|
|
61
|
+
// Return a render function from setup
|
|
62
|
+
return () => h('div', [
|
|
63
|
+
h('button', { onClick: () => count.value++ }, `Count: ${count.value}`)
|
|
64
|
+
])
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## With script setup (Not Recommended)
|
|
70
|
+
|
|
71
|
+
```vue
|
|
72
|
+
<script setup>
|
|
73
|
+
import { h, ref } from 'vue'
|
|
74
|
+
|
|
75
|
+
const count = ref(0)
|
|
76
|
+
|
|
77
|
+
// Cannot return render function from script setup
|
|
78
|
+
// Must use a separate render option or template
|
|
79
|
+
</script>
|
|
80
|
+
|
|
81
|
+
<!-- script setup typically uses templates, not render functions -->
|
|
82
|
+
<template>
|
|
83
|
+
<div>
|
|
84
|
+
<button @click="count++">Count: {{ count }}</button>
|
|
85
|
+
</div>
|
|
86
|
+
</template>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
If you need render functions with `<script setup>`, use the `render` option:
|
|
90
|
+
|
|
91
|
+
```vue
|
|
92
|
+
<script>
|
|
93
|
+
import { h, ref } from 'vue'
|
|
94
|
+
|
|
95
|
+
export default {
|
|
96
|
+
setup() {
|
|
97
|
+
const count = ref(0)
|
|
98
|
+
return () => h('button', { onClick: () => count.value++ }, count.value)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
</script>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Component Resolution Change
|
|
105
|
+
|
|
106
|
+
In Vue 3, you must also explicitly resolve components:
|
|
107
|
+
|
|
108
|
+
**Incorrect:**
|
|
109
|
+
```js
|
|
110
|
+
// Vue 2: Could use string names for registered components
|
|
111
|
+
render(h) {
|
|
112
|
+
return h('my-component', { props: { value: 1 } })
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Correct:**
|
|
117
|
+
```js
|
|
118
|
+
import { h, resolveComponent } from 'vue'
|
|
119
|
+
|
|
120
|
+
export default {
|
|
121
|
+
render() {
|
|
122
|
+
// Must resolve component by name
|
|
123
|
+
const MyComponent = resolveComponent('my-component')
|
|
124
|
+
return h(MyComponent, { value: 1 })
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Or import the component directly (preferred)
|
|
129
|
+
import { h } from 'vue'
|
|
130
|
+
import MyComponent from './MyComponent.vue'
|
|
131
|
+
|
|
132
|
+
export default {
|
|
133
|
+
render() {
|
|
134
|
+
return h(MyComponent, { value: 1 })
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Why This Changed
|
|
140
|
+
|
|
141
|
+
Vue 3's `h` is globally importable to:
|
|
142
|
+
1. Enable tree-shaking (unused features can be removed)
|
|
143
|
+
2. Support better TypeScript inference
|
|
144
|
+
3. Allow use outside of component context
|
|
145
|
+
|
|
146
|
+
## Reference
|
|
147
|
+
- [Vue 3 Migration Guide - Render Function API](https://v3-migration.vuejs.org/breaking-changes/render-function-api.html)
|
|
148
|
+
- [Vue.js Render Functions & JSX](https://vuejs.org/guide/extras/render-function.html)
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Return Render Function from setup(), Not Direct VNodes
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Returning a vnode directly from setup makes it static; returning a function enables reactive updates
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, render-function, composition-api, setup, reactivity]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Return Render Function from setup(), Not Direct VNodes
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - When using render functions with the Composition API, you must return a function that returns vnodes, not the vnodes directly. Returning vnodes directly creates a static render that never updates when reactive state changes.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Always return an arrow function from setup() when using render functions
|
|
16
|
+
- [ ] Never return h() calls directly from setup()
|
|
17
|
+
- [ ] Ensure reactive values are accessed inside the returned function
|
|
18
|
+
|
|
19
|
+
**Incorrect:**
|
|
20
|
+
```js
|
|
21
|
+
import { h, ref } from 'vue'
|
|
22
|
+
|
|
23
|
+
export default {
|
|
24
|
+
setup() {
|
|
25
|
+
const count = ref(0)
|
|
26
|
+
const increment = () => count.value++
|
|
27
|
+
|
|
28
|
+
// WRONG: Returns a static vnode, created once
|
|
29
|
+
// Clicking the button updates count.value, but the DOM never changes!
|
|
30
|
+
return h('div', [
|
|
31
|
+
h('p', `Count: ${count.value}`), // Captures count.value at setup time (0)
|
|
32
|
+
h('button', { onClick: increment }, 'Increment')
|
|
33
|
+
])
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Correct:**
|
|
39
|
+
```js
|
|
40
|
+
import { h, ref } from 'vue'
|
|
41
|
+
|
|
42
|
+
export default {
|
|
43
|
+
setup() {
|
|
44
|
+
const count = ref(0)
|
|
45
|
+
const increment = () => count.value++
|
|
46
|
+
|
|
47
|
+
// CORRECT: Returns a render function
|
|
48
|
+
// Vue calls this function on every reactive update
|
|
49
|
+
return () => h('div', [
|
|
50
|
+
h('p', `Count: ${count.value}`), // Re-evaluated each render
|
|
51
|
+
h('button', { onClick: increment }, 'Increment')
|
|
52
|
+
])
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Why This Happens
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
// What Vue does internally:
|
|
61
|
+
|
|
62
|
+
// WRONG approach - setup runs once:
|
|
63
|
+
const result = setup()
|
|
64
|
+
// result is a vnode { type: 'div', children: [...] }
|
|
65
|
+
// Vue renders this once, then has no way to re-render
|
|
66
|
+
|
|
67
|
+
// CORRECT approach - setup returns a function:
|
|
68
|
+
const renderFn = setup()
|
|
69
|
+
// renderFn is () => h('div', ...)
|
|
70
|
+
// Vue calls renderFn() on mount
|
|
71
|
+
// Vue calls renderFn() again whenever dependencies change
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Common Mistake: Mixing Template and Render Function
|
|
75
|
+
|
|
76
|
+
```vue
|
|
77
|
+
<script setup>
|
|
78
|
+
import { h, ref } from 'vue'
|
|
79
|
+
|
|
80
|
+
const count = ref(0)
|
|
81
|
+
|
|
82
|
+
// WRONG: Can't use render functions in script setup with templates
|
|
83
|
+
// This h() call does nothing
|
|
84
|
+
const node = h('div', count.value)
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<template>
|
|
88
|
+
<!-- Template is used, render function is ignored -->
|
|
89
|
+
<div>{{ count }}</div>
|
|
90
|
+
</template>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
If you need a render function with Composition API, don't use `<script setup>`:
|
|
94
|
+
|
|
95
|
+
```vue
|
|
96
|
+
<script>
|
|
97
|
+
import { h, ref } from 'vue'
|
|
98
|
+
|
|
99
|
+
export default {
|
|
100
|
+
setup() {
|
|
101
|
+
const count = ref(0)
|
|
102
|
+
return () => h('div', count.value)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
</script>
|
|
106
|
+
<!-- No template - render function is used -->
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Exposing Values While Using Render Functions
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
import { h, ref } from 'vue'
|
|
113
|
+
|
|
114
|
+
export default {
|
|
115
|
+
setup(props, { expose }) {
|
|
116
|
+
const count = ref(0)
|
|
117
|
+
const reset = () => { count.value = 0 }
|
|
118
|
+
|
|
119
|
+
// Expose methods for parent refs
|
|
120
|
+
expose({ reset })
|
|
121
|
+
|
|
122
|
+
// Still return the render function
|
|
123
|
+
return () => h('div', count.value)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## With Slots
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
import { h, ref } from 'vue'
|
|
132
|
+
|
|
133
|
+
export default {
|
|
134
|
+
setup(props, { slots }) {
|
|
135
|
+
const count = ref(0)
|
|
136
|
+
|
|
137
|
+
return () => h('div', [
|
|
138
|
+
h('p', `Count: ${count.value}`),
|
|
139
|
+
// Slots must also be called inside the render function
|
|
140
|
+
slots.default?.()
|
|
141
|
+
])
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Reference
|
|
147
|
+
- [Vue.js Render Functions with Composition API](https://vuejs.org/guide/extras/render-function.html#render-functions-jsx)
|
|
148
|
+
- [Vue.js Composition API setup()](https://vuejs.org/api/composition-api-setup.html)
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pass Slots as Functions in Render Functions, Not Direct Children
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Passing slot content incorrectly causes slots to not render or be treated as props
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, render-function, slots, children, vnode]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Pass Slots as Functions in Render Functions, Not Direct Children
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - When creating component vnodes with `h()`, children must be passed as slot functions, not as direct children. Passing children directly may cause them to be interpreted as props or fail to render.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Pass slot content as functions: `{ default: () => [...] }`
|
|
16
|
+
- [ ] Use `null` for props when only passing slots to avoid misinterpretation
|
|
17
|
+
- [ ] For default slot only, a single function can be passed directly
|
|
18
|
+
- [ ] For named slots, use an object with slot function properties
|
|
19
|
+
|
|
20
|
+
**Incorrect:**
|
|
21
|
+
```js
|
|
22
|
+
import { h } from 'vue'
|
|
23
|
+
import MyComponent from './MyComponent.vue'
|
|
24
|
+
|
|
25
|
+
// WRONG: Children array may be misinterpreted
|
|
26
|
+
h(MyComponent, [
|
|
27
|
+
h('span', 'Slot content') // May not render as expected
|
|
28
|
+
])
|
|
29
|
+
|
|
30
|
+
// WRONG: Named slots as direct properties
|
|
31
|
+
h(MyComponent, {
|
|
32
|
+
header: h('h1', 'Title'), // This is a prop, not a slot!
|
|
33
|
+
default: h('p', 'Content') // This is also a prop
|
|
34
|
+
})
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Correct:**
|
|
38
|
+
```js
|
|
39
|
+
import { h } from 'vue'
|
|
40
|
+
import MyComponent from './MyComponent.vue'
|
|
41
|
+
|
|
42
|
+
// CORRECT: Default slot as function
|
|
43
|
+
h(MyComponent, null, {
|
|
44
|
+
default: () => h('span', 'Slot content')
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
// CORRECT: Single default slot shorthand
|
|
48
|
+
h(MyComponent, null, () => h('span', 'Slot content'))
|
|
49
|
+
|
|
50
|
+
// CORRECT: Named slots as functions
|
|
51
|
+
h(MyComponent, null, {
|
|
52
|
+
header: () => h('h1', 'Title'),
|
|
53
|
+
default: () => h('p', 'Content'),
|
|
54
|
+
footer: () => [
|
|
55
|
+
h('span', 'Footer item 1'),
|
|
56
|
+
h('span', 'Footer item 2')
|
|
57
|
+
]
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
// CORRECT: With props AND slots
|
|
61
|
+
h(MyComponent, { size: 'large' }, {
|
|
62
|
+
default: () => 'Button Text'
|
|
63
|
+
})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Why Functions?
|
|
67
|
+
|
|
68
|
+
Slots in Vue 3 are functions for lazy evaluation:
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
// Slots are called by the child component when needed
|
|
72
|
+
// This enables:
|
|
73
|
+
// 1. Scoped slots (passing data back)
|
|
74
|
+
// 2. Conditional rendering (slot not called if not used)
|
|
75
|
+
// 3. Proper reactivity tracking
|
|
76
|
+
|
|
77
|
+
h(MyList, { items }, {
|
|
78
|
+
// Scoped slot - receives data from child
|
|
79
|
+
item: ({ item, index }) => h('li', `${index}: ${item.name}`)
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## The null Props Gotcha
|
|
84
|
+
|
|
85
|
+
When passing only slots, always use `null` for props:
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
// WRONG: Slots object interpreted as props!
|
|
89
|
+
h(MyComponent, {
|
|
90
|
+
default: () => 'Hello'
|
|
91
|
+
})
|
|
92
|
+
// MyComponent receives: props.default = () => 'Hello'
|
|
93
|
+
|
|
94
|
+
// CORRECT: null signals "no props, next arg is slots"
|
|
95
|
+
h(MyComponent, null, {
|
|
96
|
+
default: () => 'Hello'
|
|
97
|
+
})
|
|
98
|
+
// MyComponent receives slot correctly
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Forwarding Slots from Parent
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
export default {
|
|
105
|
+
setup(props, { slots }) {
|
|
106
|
+
return () => h(ChildComponent, null, {
|
|
107
|
+
// Forward all slots from parent
|
|
108
|
+
...slots,
|
|
109
|
+
|
|
110
|
+
// Or forward specific slots
|
|
111
|
+
default: slots.default,
|
|
112
|
+
header: slots.header
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Scoped Slots in Render Functions
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
// Parent: Receives data from child via slot props
|
|
122
|
+
h(DataTable, { data: items }, {
|
|
123
|
+
row: (slotProps) => h('tr', [
|
|
124
|
+
h('td', slotProps.item.name),
|
|
125
|
+
h('td', slotProps.item.value)
|
|
126
|
+
])
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
// Child (DataTable): Calls slot with data
|
|
130
|
+
export default {
|
|
131
|
+
props: ['data'],
|
|
132
|
+
setup(props, { slots }) {
|
|
133
|
+
return () => h('table', [
|
|
134
|
+
h('tbody',
|
|
135
|
+
props.data.map(item =>
|
|
136
|
+
// Pass data to slot function
|
|
137
|
+
slots.row?.({ item })
|
|
138
|
+
)
|
|
139
|
+
)
|
|
140
|
+
])
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Common Patterns
|
|
146
|
+
|
|
147
|
+
```js
|
|
148
|
+
// Wrapper component forwarding slots
|
|
149
|
+
h('div', { class: 'wrapper' }, [
|
|
150
|
+
h(InnerComponent, null, slots)
|
|
151
|
+
])
|
|
152
|
+
|
|
153
|
+
// Conditional slot rendering
|
|
154
|
+
h('div', [
|
|
155
|
+
slots.header?.(), // Optional chaining - only render if slot provided
|
|
156
|
+
h('main', slots.default?.()),
|
|
157
|
+
slots.footer?.()
|
|
158
|
+
])
|
|
159
|
+
|
|
160
|
+
// Slot with fallback content
|
|
161
|
+
h('div', [
|
|
162
|
+
slots.default?.() ?? h('p', 'Default content when slot not provided')
|
|
163
|
+
])
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Reference
|
|
167
|
+
- [Vue.js Render Functions - Passing Slots](https://vuejs.org/guide/extras/render-function.html#passing-slots)
|
|
168
|
+
- [Vue.js Render Functions - Children](https://vuejs.org/guide/extras/render-function.html#children)
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use resolveComponent for String Component Names in Render Functions
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: String component names don't work in Vue 3 render functions; causes silent failures or runtime errors
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, render-function, components, resolveComponent, migration]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Use resolveComponent for String Component Names in Render Functions
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - In Vue 2, render functions could use string names for globally or locally registered components. In Vue 3, you must either import components directly or use `resolveComponent()`. Using string names causes components to render as HTML elements or fail silently.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Import components directly when possible (preferred)
|
|
16
|
+
- [ ] Use `resolveComponent()` for dynamically registered components
|
|
17
|
+
- [ ] Use `resolveDynamicComponent()` for `<component :is="">` equivalent
|
|
18
|
+
- [ ] Call `resolveComponent()` inside `setup()` or the render function
|
|
19
|
+
- [ ] Handle the case when component is not found
|
|
20
|
+
|
|
21
|
+
**Incorrect:**
|
|
22
|
+
```js
|
|
23
|
+
import { h } from 'vue'
|
|
24
|
+
|
|
25
|
+
export default {
|
|
26
|
+
render() {
|
|
27
|
+
// WRONG: String names don't resolve to components
|
|
28
|
+
return h('div', [
|
|
29
|
+
h('my-component', { value: 1 }), // Renders <my-component> HTML element!
|
|
30
|
+
h('router-link', { to: '/' }, 'Home') // Also fails
|
|
31
|
+
])
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Correct (Direct Import - Preferred):**
|
|
37
|
+
```js
|
|
38
|
+
import { h } from 'vue'
|
|
39
|
+
import MyComponent from './MyComponent.vue'
|
|
40
|
+
import { RouterLink } from 'vue-router'
|
|
41
|
+
|
|
42
|
+
export default {
|
|
43
|
+
render() {
|
|
44
|
+
return h('div', [
|
|
45
|
+
h(MyComponent, { value: 1 }),
|
|
46
|
+
h(RouterLink, { to: '/' }, () => 'Home')
|
|
47
|
+
])
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Correct (resolveComponent for Registered Components):**
|
|
53
|
+
```js
|
|
54
|
+
import { h, resolveComponent } from 'vue'
|
|
55
|
+
|
|
56
|
+
export default {
|
|
57
|
+
components: {
|
|
58
|
+
MyComponent: () => import('./MyComponent.vue')
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
setup() {
|
|
62
|
+
// Resolve inside setup - component context is available
|
|
63
|
+
const MyComponent = resolveComponent('MyComponent')
|
|
64
|
+
|
|
65
|
+
return () => h('div', [
|
|
66
|
+
h(MyComponent, { value: 1 })
|
|
67
|
+
])
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Or resolve inside render function
|
|
72
|
+
export default {
|
|
73
|
+
render() {
|
|
74
|
+
const MyComponent = resolveComponent('MyComponent')
|
|
75
|
+
const RouterLink = resolveComponent('RouterLink')
|
|
76
|
+
|
|
77
|
+
return h('div', [
|
|
78
|
+
h(MyComponent, { value: 1 }),
|
|
79
|
+
h(RouterLink, { to: '/' }, () => 'Home')
|
|
80
|
+
])
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## When to Use Each Approach
|
|
86
|
+
|
|
87
|
+
| Approach | Use When |
|
|
88
|
+
|----------|----------|
|
|
89
|
+
| Direct Import | Component is known at build time (most common) |
|
|
90
|
+
| `resolveComponent()` | Component is registered globally or locally by name |
|
|
91
|
+
| `resolveComponent()` | Dynamic component selection from registered set |
|
|
92
|
+
|
|
93
|
+
## Handling Missing Components
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
import { h, resolveComponent } from 'vue'
|
|
97
|
+
|
|
98
|
+
export default {
|
|
99
|
+
setup() {
|
|
100
|
+
// resolveComponent returns the component or the string name if not found
|
|
101
|
+
const DynamicComponent = resolveComponent('MaybeRegistered')
|
|
102
|
+
|
|
103
|
+
// Check if resolution succeeded
|
|
104
|
+
if (typeof DynamicComponent === 'string') {
|
|
105
|
+
console.warn(`Component "${DynamicComponent}" not found`)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return () => h(DynamicComponent, { value: 1 })
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Dynamic Component Selection
|
|
114
|
+
|
|
115
|
+
```js
|
|
116
|
+
import { h, resolveComponent, computed } from 'vue'
|
|
117
|
+
|
|
118
|
+
export default {
|
|
119
|
+
props: ['componentName'],
|
|
120
|
+
|
|
121
|
+
setup(props) {
|
|
122
|
+
// For truly dynamic components, resolve in render function
|
|
123
|
+
return () => {
|
|
124
|
+
const Component = resolveComponent(props.componentName)
|
|
125
|
+
return h(Component, { /* props */ })
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
For the equivalent of `<component :is="componentName">`, use `resolveDynamicComponent`:
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
import { h, resolveDynamicComponent } from 'vue'
|
|
135
|
+
|
|
136
|
+
export default {
|
|
137
|
+
props: ['componentType'],
|
|
138
|
+
setup(props) {
|
|
139
|
+
return () => {
|
|
140
|
+
// Resolves string names, component objects, or built-in elements
|
|
141
|
+
const component = resolveDynamicComponent(props.componentType)
|
|
142
|
+
return h(component, { /* props */ })
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Practical Example: Tab Component
|
|
149
|
+
|
|
150
|
+
```js
|
|
151
|
+
import { h, resolveComponent, ref } from 'vue'
|
|
152
|
+
|
|
153
|
+
export default {
|
|
154
|
+
setup() {
|
|
155
|
+
const currentTab = ref('TabA')
|
|
156
|
+
const tabs = ['TabA', 'TabB', 'TabC']
|
|
157
|
+
|
|
158
|
+
return () => h('div', [
|
|
159
|
+
// Tab buttons
|
|
160
|
+
h('div', { class: 'tabs' },
|
|
161
|
+
tabs.map(tab =>
|
|
162
|
+
h('button', {
|
|
163
|
+
key: tab,
|
|
164
|
+
class: { active: currentTab.value === tab },
|
|
165
|
+
onClick: () => currentTab.value = tab
|
|
166
|
+
}, tab)
|
|
167
|
+
)
|
|
168
|
+
),
|
|
169
|
+
|
|
170
|
+
// Dynamic component based on current tab
|
|
171
|
+
h(resolveComponent(currentTab.value))
|
|
172
|
+
])
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Resolving Built-in Components
|
|
178
|
+
|
|
179
|
+
For built-in components like `<Transition>` or `<KeepAlive>`, import them directly from Vue:
|
|
180
|
+
|
|
181
|
+
```js
|
|
182
|
+
import { h, Transition, KeepAlive, Teleport, Suspense } from 'vue'
|
|
183
|
+
|
|
184
|
+
export default {
|
|
185
|
+
setup() {
|
|
186
|
+
return () => h(Transition, { name: 'fade' }, () =>
|
|
187
|
+
h('div', 'Content')
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Resolving Directives
|
|
194
|
+
|
|
195
|
+
Similar pattern for custom directives:
|
|
196
|
+
|
|
197
|
+
```js
|
|
198
|
+
import { h, resolveDirective, withDirectives } from 'vue'
|
|
199
|
+
|
|
200
|
+
export default {
|
|
201
|
+
render() {
|
|
202
|
+
const vFocus = resolveDirective('focus')
|
|
203
|
+
|
|
204
|
+
return withDirectives(
|
|
205
|
+
h('input', { type: 'text' }),
|
|
206
|
+
[[vFocus]]
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Migration from Vue 2
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
// Vue 2 (worked with registered components)
|
|
216
|
+
render(h) {
|
|
217
|
+
return h('my-component', { props: { value: 1 } })
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Vue 3 (must resolve or import)
|
|
221
|
+
import { h, resolveComponent } from 'vue'
|
|
222
|
+
|
|
223
|
+
render() {
|
|
224
|
+
const MyComponent = resolveComponent('my-component')
|
|
225
|
+
return h(MyComponent, { value: 1 }) // Note: props go directly, not in 'props' key
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Reference
|
|
230
|
+
- [Vue 3 Migration - Render Function API](https://v3-migration.vuejs.org/breaking-changes/render-function-api.html)
|
|
231
|
+
- [Vue.js Render Function API - resolveComponent](https://vuejs.org/api/render-function.html#resolvecomponent)
|