Post

Class Components in Vue are No Longer Happening

Draft updated on Invalid Date
Default avatar

By Chris on Code

Class Components in Vue are No Longer Happening

This tutorial is out of date and no longer maintained.

Introduction

An upcoming Vue update was set to have classes implemented. In React and Angular, we can create components using JavaScript classes. Some people prefer this way of component creation as it can lead to better readability. It can be a confusing tool though since people start to think of JavaScript classes as classes in other languages that have inheritance. JavaScript classes are just syntactical sugar over JavaScript functions however and classes can lead to a bit of confusion.

Current Vue Component Behavior

In Vue, we create components using objects like so:

// standalone
new Vue({ })

// using the CLI
<script>
export default { }
</script>

There was a proposal started on February 26, 2019 on GitHub that would allow us to create components with classes in addition to objects. This was targeted for the Vue 3.0 release.

What would Vue classes have looked like?

Here were the initially proposed classes:

In Browser

class App extends Vue {
  // options declared via static properties (stage 3)
  // more details below
  static template = `<div @click="increment">
      {{ count }} {{ plusOne }}
    </div>`

  // reactive data declared via class fields (stage 3)
  // more details below
  count = 0

  // lifecycle
  created() {
    console.log(this.count)
  }

  // getters are converted to computed properties
  get plusOne() {
    return this.count + 1
  }

  // a method
  increment() {
    this.count++
  }
}

In Single File Components

<template>
  <div @click="increment">
    {{ count }} {{ plusOne }}
    <Foo />
  </div>
</template>

<script>
import Vue from 'vue'
import Foo from './Foo.vue'

export default class App extends Vue {
  static components = {
    Foo
  }

  count = 0

  created() {
    console.log(this.count)
  }

  get plusOne() {
    return this.count + 1
  }

  increment() {
    this.count++
  }
}
</script>

Why classes for Vue components?

Pulled directly from the RFC on GitHub:

Vue’s current object-based component API has created some challenges when it comes to type inference. As a result, most users opting into using Vue with TypeScript end up using vue-class-component. This approach works, but with some drawbacks:

  • Internally, Vue 2.x already represents each component instance with an underlying “class”. We are using quotes here because it’s not using the native ES2015 syntax but the ES5-style constructor/prototype function. Nevertheless, conceptually components are already handled as classes internally.
  • vue-class-component had to implement some inefficient workarounds in order to provide the desired API without altering Vue internals.
  • vue-class-component has to maintain typing compatibility with Vue core, and the maintenance overhead can be eliminated by exposing the class directly from Vue core.

The primary motivation of native class support is to provide a built-in and more efficient replacement for vue-class-component. The affected target audience are most likely also TypeScript users.

The API is also designed to not rely on anything TypeScript specific: it should work equally well in plain ES, for users who prefer using native ES classes.

Note: We are not pushing this as a replacement for the existing object-based API - the object-based API will continue to work in 3.0.

Classes are abandoned. What now?

There are two major reasons why the Class API proposal was dropped:

Composition functions and Classes and Objects would allow us to make the same component 3 different ways. Vue has always focused on developer experience so it’s comforting to see them try to simplify the developer experience again. They feel that 3 ways to do the same thing is not the best.

Composition Functions

With the coming composition functions, TypeScript support is one of the main benefits. Support is better in this approach than in the classes approach.

With the two new APIs #22 Advanced Reactivity API and #23 Dynamic Lifecycle Injection, we have a new way of declaring component logic: using function calls.. These are inspired by React Hooks.

In composition functions, a component’s logic will happen in a new setup() method. It is pretty much data() but gives us more flexibility using function calls inside of it.

// everything tree-shakable
import {
  value,
  computed,
  watch,
  onMounted,
  inject
} from 'vue'

const App = {
  // same as before
  props: {
    a: String,
    b: Number
  },

  // same as before
  components: {
    // ...
  },

  setup(props) {
    // data
    const count = value(1)

    // computed
    const plusOne = computed(() => count.value + 1)

    // methods
    function inc() {
      count.value++
    }

    // watch
    watch(() => props.b + count.value, val => {
      console.log('changed: ', val)
    })

    // lifecycle
    onMounted(() => {
      console.log('mounted!')
    })

    // dependency injection
    const injected = inject(SomeSymbol)

    // other options like el, extends and mixins are no longer necessary

    // expose bindings on render context
    // any value containers will be unwrapped when exposed
    // any non-containers will be exposed as-is, including functions
    return {
      count,
      plusOne,
      inc,
      injected
    }
  },

  // template: `same as before`,

  render({ state, props, slots }) {
    // `this` points to the render context and works same as before (exposes everything)
    // `state` exposes bindings returned from `setup()` (with value wrappers unwrapped)
  }
}

Conclusion

I’m excited to see where the Vue team goes with these “composition functions”. I like the idea of thinking of our components more as composed parts since that’s more in line with a JavaScript way of thinking. Classes lead to people thinking in a more object-oriented way.

This also leans towards a thought process that is similar to how React is moving with React Hooks. The “composition functions” also allow for better TypeScript support which in turn leads to a better developer experience and tooling.

I’m looking forward to seeing where Vue goes next. I don’t mind Vue’s way of declaring components with objects and it’s looking good with the way they are sticking with it.

What are your thoughts on the dropping of the classes proposal?

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
Chris on Code

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel