I am migrating to Vue SFC and have problem using computed property.
With the following code, I want to create two rows, and the visibility of the bottom row (the content row) can be toggled by clicking the top row (the title row).
<!-- components/Note.vue -->
<script setup>
import { marked } from "marked";
import { ref, computed } from "vue";
const props = defineProps({
id: Number,
title: String,
create: String,
content: String
});
const showContent = ref(false);
const elContent = ref(null);
const scrollHeight = computed(() => {
return elContent.value.scrollHeight + "px";
});
const markedContent = computed(() => {
return marked.parse(content.value);
})
</script>
<template>
<div class="row" @click="showContent=!showContent">
<div class="col-9">{{ title }}</div>
<div class="col-3">{{ create }}</div>
</div>
<div class="row" :style="{height:showContent?scrollHeight:0}" ref="elContent">
<div class="col">{{ markedContent }}</div>
</div>
</template>
Here is the error message
[Vue warn]: Unhandled error during execution of render function (9)
"
"
" at <Note"
"id=27"
"title=\"1Lorem Ipsum\""
" ..."
">"
"
"
" at <App>"
[Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug. Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/core (9)
"
"
" at <Note"
"id=27"
"title=\"1Lorem Ipsum\""
" ..."
">"
"
"
" at <App>"
Unhandled Promise Rejection: ReferenceError: Can't find variable: content
However, if I don't use computed property, but the marked.parse
method directly in the template, then everything works smoothly.
<!-- This is fine -->
<div class="row" :style="{height:showContent?scrollHeight:0}" ref="elContent">
<div class="col">{{ marked.parse(content) }}</div>
</div>
I hope someone can tell me why this happens and how should I use computed property in script setup.
Use the props.probName
pattern to access props in script-setup files. However, in the template section, you must use probName
directly.
So in your case, use props.content
instead of content
to address the issue.
const markedContent = computed(() => {
return marked.parse(props.content);
//return marked.parse(props.content.value);
})
The props
name comes from the definition of your props, where you choose a variable name to hold all properties.
// Here you've defined a variable name (props) that represents all properties
const props = defineProps({
id: Number,
title: String,
create: String,
content: String
});
If you wish to access props directly (as in the template), you can destruct the props
at the place:
const {content, id, title, create} = defineProps({
id: Number,
title: String,
create: String,
content: String
});
const markedContent = computed(() => {
return marked.parse(content);
})
Keep in mind that destructing props is not straightforward. It brings more coding and complexity, therefore I avoid it.
You need to always access props as props.x in order to retain reactivity. This means you cannot destructure defineProps because the resulting destructured variables are not reactive and will not update. (link)
To tackle the losing reactivity problem, you need to either use toRef
manually or leverage the Vue Macros plugin.
Reactivity Transform was an experimental feature, and has been deprecated