Ted Morin
Ted Morin

Reputation: 668

Why is "this" undefined in Vue Composition API setup function?

I have a Vue component using v3's composition API:

<template>
  <input type="checkbox" v-model="playing" id="playing" @input="$emit('play', $event.target.value)" />
  <label for="playing" >{{ playing ? 'Pause' : 'Play' }}</label>
</template>
<script>
export default {
  props: {
    done: Boolean
  },
  setup(props) {
    const playing = ref(true)
    watchEvent(() => {
      if (props.done) {
        playing.value = false
        this.$emit('play', playing.value)
      }
    }
    return { playing }
  }
}
</script>

When the watchEvent runs, I get the error Cannot read property "$emit" of undefined. It doesn't look like I'm using the wrong type of function (arrow versus normal function).

It seems like this is undefined throughout setup() regardless of whether it's a function or an arrow function.

Upvotes: 10

Views: 15584

Answers (2)

Steve
Steve

Reputation: 1376

For Vue 3 Composition API, from the documentation:

...we cannot directly access this.$router or this.$route anymore. Instead we use the useRouter and useRoute functions:

import { useRouter, useRoute } from 'vue-router'

export default {
  setup() {
    const router = useRouter()
    const route = useRoute()

    function pushWithQuery(query) {
      router.push({
        name: 'search',
        query: {
          ...route.query,
          ...query,
        },
      })
    }
  },
}

Upvotes: 0

Ted Morin
Ted Morin

Reputation: 668

The setup function in the Vue Composition API receives two arguments: props and context.

The second argument provides a context object which exposes a selective list of properties that were previously exposed on this in 2.x APIs:

const MyComponent = {
  setup(props, context) {
    context.attrs // Previously this.$attrs
    context.slots // Previously this.$slots
    context.emit // Previously this.$emit
  }
}

It's important to note that it's not okay to destructure props (you'll lose reactivity), but it's okay to destructure context.

So the code example in the question, use setup(props, { emit }) and then replace this.$emit with emit.

Upvotes: 16

Related Questions