36

I'm trying to get computed to work in <script setup>:

<template>
  <div>
    <p>{{ whatever.get() }}</p>
  </div>
</template>


<script setup>
import {computed} from "vue";

const whatever = computed({
    get() {
        console.log('check')
        return 'check?';
    }
})
</script>

The console.log() comes through but the return statement seems to throw an error:

check
Vue warn]: Unhandled error during execution of render function 
  at <Cms>
Uncaught TypeError: $setup.whatever.get is not a function
at Proxy.render (app.js?id=d9e007128724c77a8d69ec76c6c081a0:39550:266)
at renderComponentRoot (app.js?id=d9e007128724c77a8d69ec76c6c081a0:25902:44)
at ReactiveEffect.componentUpdateFn [as fn] (app.js?id=d9e007128724c77a8d69ec76c6c081a0:30019:57)
at ReactiveEffect.run (app.js?id=d9e007128724c77a8d69ec76c6c081a0:23830:29)
at setupRenderEffect (app.js?id=d9e007128724c77a8d69ec76c6c081a0:30145:9)
at mountComponent (app.js?id=d9e007128724c77a8d69ec76c6c081a0:29928:9)
at processComponent (app.js?id=d9e007128724c77a8d69ec76c6c081a0:29886:17)
at patch (app.js?id=d9e007128724c77a8d69ec76c6c081a0:29487:21)
at render (app.js?id=d9e007128724c77a8d69ec76c6c081a0:30630:13)
at mount (app.js?id=d9e007128724c77a8d69ec76c6c081a0:28882:25)

What am I doing wrong?

2 Answers 2

55

In <template>:

Getter only:

  • {{ myVal }}
  • <p v-text="myVal" />

Getter and setter:

  • <input v-model="myVal">

Important: Do not use myVal.get() or myVal.set(value)! Use:

  • getting: myVal
  • setting (assignment): myVal = value

In <script setup>:

Getter only:

const someReactiveRef = ref(null)
const myVal = computed(() => someReactiveRef.value)

Getter & setter:

const someReactiveRef = ref(null)

const myVal = computed({
  get() {
    return someReactiveRef.value
  },
  set(val) {
    someReactiveRef.value = val
  }
})
// myVal can now be used in `v-model`

When the reactive ref is coming from a reactive() object's property, you don't need the .value in either the setter or the getter. Example:

const store = reactive({
  someProp: null
})

const myVal = computed({
  get() {
    return store.someProp
  },
  set(val) {
    store.someProp = val
  }
})

Remember you can always use computed inside reactive. Example:

const { createApp, reactive, computed, toRefs } = Vue
createApp({
  setup() {
    const state = reactive({
      firstName: 'John W.',
      lastName: 'Doe',

      // getter + setter
      fullName: computed({
        get() {
          return [state.firstName, state.lastName].join(' ')
        },
        set(val) {
          const [last, ...rest] = val.split(' ').reverse()
          state.firstName = rest.reverse().join(' ')
          state.lastName = last
        }
      }),

      // getter only:
      name: computed(() => state.fullName)
    })
    return toRefs(state)
  }
}).mount('#app')
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
<div id="app">
  <input v-model="firstName" />
  <input v-model="lastName" />
  <input v-model="fullName" />
  <pre v-text="{ firstName, lastName, fullName, name }"></pre>
</div>

Important notes:

  • when passing a non-reactive reference to a computed, Vue will warn you (the computed wrapper is unnecessary).
  • when passing it a ref which contains a cyclic dependency (e.g: a component instance) Vue will again warn you and advise on using either shallowRef or markRaw.
Sign up to request clarification or add additional context in comments.

4 Comments

How to access myVal inside the script section not the template?
@Bill to access computed property value in the code, like setup function, use computed property name with .value appended e.g. myVal.value
Did you mean state.someProp instead of store.someProp?
@Shadow, you're right. I meant to name the reactive store (but I typically name it state when I'm inside a component). But for the purpose of this answer, it should called store. Fixed it. Thanks.
1

Computed properties appear as fields. This is true regardless of whether you pass in a function (as in computed(() => /*...*/)) or an object with a get() method (which is equivalent here if you don't provide a set() method).

Your template should simply use the name of your computed property, which here is whatever.

<template>
  <div>
    <p>{{ whatever }}</p>
  </div>
</template>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.