Rendering discrepancy between components written in JS and SFC
Version
3.1.2
Reproduction link
https://jsfiddle.net/3udtwzae/
Steps to reproduce
<template>
<pre>{{ options }}</pre>
</template>
<script>
import { computed } from 'vue'
function useOptions(props) {
const options = computed(() => props.options.map(o => ({
label: o,
value: o,
})))
return { options }
}
export default {
props: {
options: { type: Array, required: true }
},
setup(props) {
const o = useOptions(props)
return {
// passed directly works!
// options: o.options,
...o,
}
}
}
</script>
What is expected?
In both cases should render pre
tag with content "[{"label":"foo","value":"foo"}]"
What is actually happening?
SFC (Options.vue) renders component's prop options
instead of the value of the computed property with the same name when is not directly exposed in the setup's return statement but is rather spread from composable function.
// Options.vue
setup(props) {
const { options } = useOptions(props)
return {
// passed directly works!!!!!
// options: o.options,
options,
}
}
or just return options
instead { options }
on useOptions
.
I know that now but why does it matter if I return a property XYZ
directly or if I spread an object with a property XYZ
? should it work the same in both cases? Shouldn't the setup context be taken into account first when accessing properties in the template? and why it currently works differently in the reproduction examples I provided.
I know that now but why does it matter if I return a property
XYZ
directly or if I spread an object with a propertyXYZ
? should it work the same in both cases? Shouldn't the setup context be taken into account first when accessing properties in the template? and why it currently works differently in the reproduction examples I provided.
The samples are not the same, you are wrapping it { options }
, you should return options
to be the same.
but you are right, not working... working with:
function useOptions(props) {
const options = computed(() => props.options.map(o => ({
label: o,
value: o,
})))
return options
}
This is because you are using the same name for the computed and prop (options). Make sure to name it differently. It works with the script setup because it allows variable shadowing while the options do not. This will make more sense if you take a look at the generated JS for both Option components
@posva I am still kind of confused by this behavior. You're saying "Make sure to name it differently." but it works when I return computed named options
directly in the setup. Shouldn't the component then render oprions
from props (["foo"]
) and not my computed property?
It works with the script setup ...
do you have <script setup>
in mind? because I am talking about normal SFC component
function useOptions() {
const options = computed(() => [])
return { options }
}
export default {
props: { options: Array },
setup() {
const { options } = useOptions()
return {
options
}
}
}
export default {
props: { options: Array },
setup() {
return {
...useOptions()
}
}
}
in both cases I return options
in the setup, both examples do the same thing but component works differently ¯_(ツ)_/¯
If the current behavior is correct maybe this needs to be somehow mentioned in the docs?