Use old instance properties in Composition API in Vue.js 3

Before starting, let me remind you that our friends from VueSchool are offering a crazy 40% discount during black Friday. Included even for existing subscribers, I wouldn’t miss the chance and get it using the previous link! Let’s go to the tip if you’ve already done it.

In the last tip “Easily switch to Composition API in Vue.js 3” I explained how to migrate the basic parts of a Vue.js Object API component to the new Composition API.

However, that’s not all. What happens with all instance properties we used to have, such as this.$emit, this.$slots, this.$attrs and so? They were on the this component instance, but there is no this in Composition API.

In the same line, in the last tip I didn’t use props, and you used to access them via this in the component instance. How the heck can you access it now?

The thing is, I haven’t explained the arguments of the setup function when using Composition API.

Effectively, the first parameter of the setup function receives all the component properties. Following the example from the last tip, let’s add two properties to use as the initial values for the money and delta local state variables:

export default {
  props: {
    money: {
      type: Number,
      default: 10
    },
    delta: {
      type: Number,
      default: 1
    }
  },
  setup(props) {
    const money = ref(props.money);
    const delta = ref(props.delta);

    // ...
  }
};

Easy-peasy. Nothing else changes about props management aside from this in Vue.js components.

Now, what about all other instance properties and methods, such as $emit? You can find them in the second argument of the setup function: the setup context object.

The setup context has the following shape:

interface SetupContext {
  readonly attrs: Record<string, string>;
  readonly slots: { [key: string]: (...args: any[]) => VNode[] };
  readonly parent: ComponentInstance | null;
  readonly root: ComponentInstance;
  readonly listeners: { [key: string]: Function };
  emit(event: string, ...args: any[]): void;
}

And what’s even cooler, it’s that we can use object destructuring on the setup context and the reactivity is not lost!

To illustrate it, I’m going to modify the last example and add some logging in the onMounted hook as well as emitting a money-changed event when that changes:

setup(props, { emit, attrs, slots }) {
    // State
    const money = ref(props.money);
    const delta = ref(props.delta);

    // Hooks
    onMounted(() => {
      console.log("Money Counter (attrs): ", attrs);
      console.log("Money Counter (slots): ", slots);
    });

    // Watchers
    const moneyWatch = watch(money, (newVal, oldVal) =>
      emit("money-changed", newVal)
    );
}

That’s it! Now you’re already able to use most of Vue.js component instance properties and methods.

But probably you’ve realized not all are in the render context… What about this.$refs? And plugins that inject stuff such as this.$store?

No worries, I’ll cover that in the next tips! No spoilers, stay with me and you’ll stay cool!

By the way, if you’re a live-coding peep you should check the code from this tip working in this CodeSandbox!

That’s it for today’s tip!

Remember you can read this tip online (with copy/pasteable code), and don’t forget to share VueDose with your colleagues, so they also know about these tips as well!

See you soon.

Don't miss anything! Continue reading on VueDose

Start saving time and get a tip about the Vue ecosystem every week, right in your inbox.

    Latest Vue Jobs