vuejs / docs

📄 Documentation for Vue 3
https://vuejs.org
Other
2.92k stars 4.38k forks source link

Props (Composition API) #2185

Open ckhatton-transreport opened 1 year ago

ckhatton-transreport commented 1 year ago

https://vuejs.org/guide/components/props.html#props-declaration

When it comes to the example of passing an object of props, it isn't clear that you still need to use const props = if you want to use those props.

The example should instead be:

// in <script setup>
const props = defineProps({
  title: String,
  likes: Number
})

And the TypeScript example:

<script setup lang="ts">
const props = defineProps<{
  title?: string
  likes?: number
}>()
</script>

:octocat:

jaredmcateer commented 1 year ago

To be more clear you only need to assign a props variable if you plan to use the prop in the script section and the first example on the Props docs page demonstrates this (but doesn't make it explicit).

For example this works:

<script setup lang="ts">
defineProps<{ title: string; likes: number }>();
</script>

<template>
  <h1>{{ title }}</h1>
  <h2>{{ likes }} likes</h2>
</template>

SFC Playground

Examining the transpiled code makes this clear

<script setup lang="ts">
const props = defineProps<{ title: string; likes: number }>();
</script>
...
const __sfc__ = /*#__PURE__*/ _defineComponent({
    __name: 'Comp',
    props: {
        title: null,
        likes: null
    },
    setup(__props) {

        const props = __props; // <-- unused variable

        return (_ctx, _cache) => {
            return (_openBlock(), _createElementBlock(_Fragment, null, [
                _createElementVNode("h1", null, _toDisplayString(__props.title), 1 /* TEXT */ ),
                _createElementVNode("h2", null, _toDisplayString(__props.likes) + " likes", 1 /* TEXT */ )
            ], 64 /* STABLE_FRAGMENT */ ))
        }
    }

})
ckhatton-transreport commented 1 year ago

That is good to know. I am not sure if it was because of my dyslexia, but that was not that apparent when I first read it - maybe it needs to be illustrated more clearly or stipulated in a block-quote?

Note: You only need to assign a props variable if you plan to use the prop in the script section.

ne0guille commented 11 months ago

That is good to know. I am not sure if it was because of my dyslexia, but that was not that apparent when I first read it - maybe it needs to be illustrated more clearly or stipulated in a block-quote?

Note: You only need to assign a props variable if you plan to use the prop in the script section.

i've just learned this too, but to be fair taking a 2nd look at the doc there are examples of props definition without using a variable

<script setup lang="ts"> defineProps<{ title?: string likes?: number }>() </script>

https://vuejs.org/guide/components/props.html#prop-passing-details

jaredmcateer commented 11 months ago

I've personally come to the opinion that you should always be using const props = and then in your templates using props.var rather than relying on Vue's magic to do it for you. Not using props as a namespace creates ambiguity in the template when you have code like this:

<script setup lang="ts">
defineProps<{ foo: string }>();
const foo = ref('Hello world');
</script>

<template>
<div>{{ foo }}</div>
</template>

It is unclear for the reader of the code whether the template is displaying props.foo or foo.value in the template. You just have to know that Vue will prefer locally created variables over props in the template. And even then the reader may not know the intention of the authors code and maybe this is a subtle bug. Better to always be explicit (and if possible avoid shadowing props variables in the first place.)

<script setup lang="ts">
const props = defineProps<{ foo: string }>();
const bar = ref('Hello world');
</script>

<template>
<div>{{ props.foo }}</div>
</template>
ranjbarreza commented 1 month ago
<script setup lang="ts">
defineProps<{ foo: string }>();
const foo = ref('Hello world');
</script>

I think in that case you already get an error that 'foo' is already defined. Cannot redeclare block-scoped variable 'foo'..

I'm using eslint, maybe that makes it more clear.

jaredmcateer commented 1 month ago

I don't see that error in a default eslint setup. When creating a new project with vue's recommend npm create vue@latest you do get the following error

3:7  error    Duplicate key 'foo'. May cause name collision in script or template tag  vue/no-dupe-keys

Which is fine, but that relies on the linter rules to be setup correctly. I think my reasoning for being explicit still stands.