-
-
Notifications
You must be signed in to change notification settings - Fork 8.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(compiler-sfc): introduce defineModel
macro and useModel
helper
#8018
Conversation
defineModel
macrodefineModel
macro and useModel
helper
ed8c3fb
to
fdd91c6
Compare
const modelValue = defineModel({ type: null, required: false, default: 0 })
// generated code
const __sfc__ = _defineComponent({
props: {
"modelValue": { required: true, ...{ type: null, required: false, default: 0 } },
},
}) Can this output be optimized to Second thing. Why is type const modelValue = defineModel<any>()
// output
"modelValue": { type: Unknown, required: true } |
@sqal Thanks for reviewing. The first issue can be optimized but it only happened in development mode. So now it's not very worth improving it. The second issue is fixed now. |
@@ -1391,12 +1509,12 @@ const emit = defineEmits(['a', 'b']) | |||
expect(content).toMatch(`const props = __props`) | |||
|
|||
// foo has no default value, the Function can be dropped | |||
expect(content).toMatch(`foo: null`) | |||
expect(content).toMatch(`bar: { type: Boolean }`) | |||
expect(content).toMatch(`foo: { required: true }`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should be avoided - in production mode required
is useless since there will be no warnings / checks, so we should generate the minimal amount of options to save bundle size.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it's intentional. useModel
requires required
option to check if a prop is passive.
BTW required: false
can still be omitted. (done)
packages/compiler-sfc/__tests__/compileScriptPropsDestructure.spec.ts
Outdated
Show resolved
Hide resolved
runtimeOptions += genRuntimeEmits(typeDeclaredEmits) | ||
} | ||
|
||
let propsDecl = genRuntimeProps() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let propsDecl = genRuntimeProps() | |
const propsDecl = genRuntimeProps() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hope ESLint prefer-const
can be enabled.
The latest updates on your projects. Learn more about Vercel for Git ↗︎ 1 Ignored Deployment
|
* modelValue.value = "hello" | ||
* | ||
* // default model with options | ||
* const modelValue = defineModel<stirng>({ required: true }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* const modelValue = defineModel<string>({ required: true })
@sxzz Why is component that has Example from your demo: <script setup>
import Comp from './Comp.vue'
import {ref} from 'vue'
const count = ref(0)
</script>
<template>
<Comp /> <!-- NOT WORKING -->
<hr />
<Comp v-model="count" />
<hr />
<input v-model="count"/>
{{ count }}
</template>
<script setup lang=ts>
import { ref } from 'vue'
const modelValue = defineModel<number>({ default: 0 })
</script>
<template>
<button @click="modelValue++">+</button>
{{modelValue}}
</template> So you have to write a bunch of excess code to fix it: <script setup lang=ts>
import { ref, watchEffect } from 'vue'
const modelValue = defineModel<number>({ default: 0 })
const counter = ref(modelValue.value)
watchEffect(() => {
counter.value = modelValue.value
})
</script>
<template>
<button @click="() => {counter++; modelValue++;}">+</button>
{{counter}}
</template> |
@Merkushin-AY You can see vuejs/rfcs#503 Local Mode Chapter. |
When will this no longer be experimental and opt-in? Should I avoid using it in my project until it's stable? |
RFC: vuejs/rfcs#503
Summary
This PR introduces a new macro called
defineModel
that enhances the developer experience when using two-way binding props. WithdefineModel
, v-model props can be declared and mutated like a ref.<script setup>
only feature.update:propName
event.defineModel
, and it's disabled by default.The PR also includes a new runtime helper function called
useModel
. This function is used as the underlying output ofdefineModel
, and can be used in plainsetup()
functions where SFC isn't used. It works similarly to useVModel from VueUse.Basic Usage
defineModel
If the first argument is a string, it will be used as the prop name; Otherwise the prop name will default to "modelValue". In both cases, you can also pass an additional object which will be used as the prop's options.
The options object can also specify an additional option,
local
. When set totrue
, the ref can be locally mutated even if the parent did not pass the matchingv-model
.See demo
useModel
See demo
Related:
defineModels
from Vue MacorsuseVModel
from VueUse