DEV Community

Cover image for Vue 3 is Coming!
Gaute Meek Olsen
Gaute Meek Olsen

Posted on • Updated on • Originally published at gaute.dev

Vue 3 is Coming!

I have been playing around with Vue 3, which is really cool. So let me share some of what I have learned. According to their roadmap, they have planned for a release at the end of Q2 (April, May, Juni) 2020. Now it is in Alpha, but it will probably be a Beta release soon.

Note that this article is time-sensitive. As code changes could happen, better best practices can emerge and better documentation will be available. But if you want a head start, this article can help you, written on 2020-04-08.

Get Started Today

You can create a Vue 3 project today if you like. Just remember that there isn't any official documentation yet and code changes might occur until the release. I have created a GitHub repository with a project you can play around with and see some example code. The readme contains information on how to set up a Vue 3 project, as well as resources to keep you updated and articles, videos and podcasts about Vue 3.

Improvements

The biggest change in Vue 3 is that it is completely re-written under the hood. This means for us developers that things will be pretty much the same. The result otherwise is a much better product. Vue was already fast, but now it has a huge performance and memory improvement, it is better at static tree hoisting and tree shaking(dead code elimination).

Fast

They have also written Vue 3 in TypeScript, which makes the project more maintainable for the Vue team. But it also has some benefits for us developers, even if you are using JavaScript or TypeScript, you will get better IntelliSense and typeahead.

They use RFCs (Request For Comments) for every change to involve the community in the decisions that are being made.

Changes

Composition API

There is a new optional way to write the JavaScript part of your component. They have named the way we do it today as the Options API, where you have an object with the data, methods, computed, watch, etc. properties. This is still valid in Vue 3. The composition API is just an additive way. I will keep it short, but for a better explanation, you can go here.

Let's see the skeleton of the component object.

// Import the API's you are using for the component
import { ref, reactive, computed } from 'vue';

export default {
  // the setup method where logic happens
  setup(){
    return { /* return what logic is exposed to the template */ }
  }
}
Enter fullscreen mode Exit fullscreen mode

Now to the exciting part. Let's write some setup code. ref and reactive are used to store reactive variables.

setup(){
  //Let's have two different reactive values
  const counter = ref(0);
  const state = reactive({
    count: 0
  });

  //Update the values
  counter.value++;
  state.count++;

  return { counter, state }
}
Enter fullscreen mode Exit fullscreen mode

As you can see the ref and reactive can do pretty much the same. ref are mainly for primitive types and arrays. While reactive holds an object. Which you use will be up to you, but I think with time best practices for what to use where will emerge.

We are already used to computed properties, methods, watch. The principle is the same. It's just written a little differently.

We also have watchEffect which is very similar to watch, but you don't have to tell it which values to listen to, it will run on every dependency used inside the function.

setup(){
  const counter = ref(0);

  const double = computed(() => counter.value * 2);

  const addToCounter = toAdd => counter.value += toAdd;

  watch(counter, () => console.log('counter updated'));

  return { double, addToCounter }
}
Enter fullscreen mode Exit fullscreen mode

I'm using arrow functions here, but it could be normal functions. And the code doesn't need to be inside the setup method, it could be outside the Vue object, it could be in another file, the thing that matters is that the setup returns the methods and reactive values.

This got me thinking, could this be used to create a really simple global reactive state? The answer is yes.

globalShoppingCart.js:

import { reactive, computed } from 'vue';

const shoppingCart = reactive({
  items: [],
  totalPrice: computed(() => shoppingCart.items.reduce((acc, item) => acc + item.price, 0))
});

const addItem = item => shoppingCart.items.push(item);

export { addItem, shoppingCart }
Enter fullscreen mode Exit fullscreen mode

item.vue:

<template>
    <h1>Ball</h1>
    <button @click="addItem({name: 'ball', price: 99})">Add to Cart</button>
</template>

<script>
import { addItem } from '@/globalShoppingCart'

export default {
    setup(){
        return { addItem }
    }
}
</script>
Enter fullscreen mode Exit fullscreen mode

cart.vue:

<template>
    <h1>Cart</h1>
    <span>Items: {{ shoppingCart.items.length }}</span>
    <span>Price: {{ shoppingCart.totalPrice }}</span>
</template>

<script>
import { shoppingCart } from '@/globalShoppingCart'

export default {
    setup(){
        return { shoppingCart }
    }
}
</script>
Enter fullscreen mode Exit fullscreen mode

That's cool! We don't have to deal with that many props and emits anymore.

It also works great for re-using code. Let's have our like and super like functionality in its own JavaScript file, but everyone using the file will have its own state.

likes.js:

import { ref } from "vue"

const getLikes = () => {
    const likes = ref(0)
    const superLike = () => likes.value += 1000;
    return { likes, superLike }
}

export { getLikes }
Enter fullscreen mode Exit fullscreen mode

hearts.vue:

<template>
    <div>
        {{likes}}๐Ÿงก
        <button @click="likes++">Love</button>
        <button @click="superLike">๐Ÿ’•๐Ÿ’•๐Ÿ’•</button>
    </div>
</template>

<script>
import { getLikes } from '@/likesOwn';
export default {
    setup(){
        return { ...getLikes() }
    }
}
</script>
Enter fullscreen mode Exit fullscreen mode

To the last part of the composition API, lifecycle hooks. It's pretty much the same, but you can have them inside the setup method. You can also have multiple of the same.

setup(){
  onMounted(() => console.log('DOM is ready'));
  onMounted(() => console.log('mounted called again'));
}
Enter fullscreen mode Exit fullscreen mode

One thing, there doesn't exist a thing such as onCreated! This code should be inside the setup method. Since the setup method will run once at the very start of the component. So fetching data and such is a good place to have inside the setup method.

The composition API is optional, it can be used together with the options API in the same component. The composition API will help with keeping associated logic close to each other, moving setup code to its own files and re-using code. The concepts of Vue is pretty much the same, your data will be ref or reactive and we are used to watch, computed, and lifecycle hooks.

Fragment

Have you ever notices that every template needs to have only one child? This is annoying because it pollutes the DOM and gives you more code and indentations.

Not anymore

<template>
  <h1>This is</h1>
  <h2>completely</h2>
  <h3>fine! :)</h3>
</template>
Enter fullscreen mode Exit fullscreen mode

Suspense

Suspense is a new feature introduced in Vue 3. When your component is not ready, it gives you an easy way to show a loading spinner for example.

Let's have an async setup method that fetches some data.

async setup(){
  const response = await fetch('someurl');
  const data = await response.json();
  return { data }
}
Enter fullscreen mode Exit fullscreen mode

Now, this might take some time. When will your component be ready? Just have your parent component use suspense like this.

<template>
  <Suspense>
    <template #default>
      <MyChildComponenta/> //the component with async setup
    </template>
    <template #fallback>
      <div>Loading...</div>
    </template>
  </Suspense>
</template>
Enter fullscreen mode Exit fullscreen mode

Teleport

Note that Teleport was named Portal until recently, so if you are reading some other articles they might be outdated.

Teleport gives us the ability to teleport some HTML code to another place in our application outside the component.

Somewhere in your application, you have an element with an id:

<div id="arrival-spot"></div>
Enter fullscreen mode Exit fullscreen mode

Now you can have another component target that element.

<template>
  <div>
    <span>I'm still in my component</span>
    <Teleport to="#arrival-spot">
      <span>Woho, I can teleport \o/ </span>
    </Teleport>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Multiple v-model

Now you can have multiple v-models on your custom component when you want to bind different values.

<HumanStats v-model:age="human.age" v-model:height="human.height"/>
Enter fullscreen mode Exit fullscreen mode

Transition

Just a small naming change for transitions. I found v-enter-active, v-enter, v-enter-to a little confusing. In Vue 3 v-enter is renamed to v-enter-from and v-leave to v-leave-from. Now the transitions make more sense, a class for when it is active, a class for what it transitions from and a class for what it transitions to.

Filter removed

<!-- before -->
{{ date | format }}

<!-- after -->
{{ format(date) }}
Enter fullscreen mode Exit fullscreen mode

In Vue 2 we had filter methods to run our values through when displaying the values. This is now removed to enforce that inside the brackets is just valid JavaScript. Computed properties or methods should be used instead, which is fine and just another way of writing the code.

App configuration

In Vue 2 we have the global Vue object which we configure. In Vue 3 every configuration is scoped to a certain Vue application defined with createApp.

main.js:

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.use(/* ... */)
app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)

app.mount('#app')
Enter fullscreen mode Exit fullscreen mode

Conclusion

I am very excited about Vue 3. I think this will keep Vue as one of the best frameworks out there.

Top comments (16)

Collapse
 
sonicoder profile image
Gรกbor Soรณs

Nice summary!

Do you know anything about what will happen with testing? vue-test-utils is broken with Vue 3.

In the meantime, I'm also experimenting with Vue on the TodoMVC app. Good to see others are doing it also.

Collapse
 
gautemeekolsen profile image
Gaute Meek Olsen

Looks like vue-test-utils for Vue 3 has reached alpha today :) Check out vue-test-utils-next

Collapse
 
sonicoder profile image
Gรกbor Soรณs

Thanks, upgraded, it works with minor bugs

Collapse
 
gautemeekolsen profile image
Gaute Meek Olsen

Thank you!

I'm not quite sure, I haven't looked into it.

Nice, thank you for sharing the Todo app :D

Collapse
 
mburszley profile image
Maximilian Burszley

So filters are gone with v3? Is that a breaking change?

Collapse
 
gautemeekolsen profile image
Gaute Meek Olsen

Yes, it is. The main reason is that JavaScript has this ESNext Proposal: The Pipeline Operator. This may or may not happen, but if JavaScript introduces this, it would break Vue I think. So they are thinking ahead and keeping what's inside the brackets to only be valid JavaScript.

Collapse
 
mburszley profile image
Maximilian Burszley

Interesting; thanks for that link. Is the proposal gaining traction? I've never heard of it before this.

Thread Thread
 
gautemeekolsen profile image
Gaute Meek Olsen

I'm not quite sure actually, first time hearing about it myself :)

Collapse
 
sidecut profile image
Jim R

The pipe syntax is just a way of composing functions. That syntax has gone away in favor of the familiar way of composing functions.

So x | y | z can be rewritten as z(y(x)).

That being said, I think there's a strong argument to be made for keeping the filter pipe syntax. It's used in unix, a lot of functional languages, Vue2, other JS frameworks, etc. It's a terrific idea.

Collapse
 
mburszley profile image
Maximilian Burszley

I know it's purpose. I don't know what they gain by removing it. It's also quite popular in jinja2

Collapse
 
zearin profile image
Zearin

Well, they are going with a new major version in Vue 3โ€”so, breaking changes are to be expected.

Collapse
 
mburszley profile image
Maximilian Burszley

Expected, but not mandatory. SemVer also reserves bumping major versions for a sweeping feature introduction (like functional components).

Collapse
 
sidecut profile image
Jim R

Is this a typo, or are both v-enter and v-leave renamed to the same thing?

"In Vue 3 v-enter is renamed to v-enter-from and v-leave to v-enter-from."

Collapse
 
gautemeekolsen profile image
Gaute Meek Olsen

It was a typo. Thank you for correcting me :) I have updated the article now.

  • Rename the v-enter transition class to v-enter-from
  • Rename the v-leave transition class to v-leave-from
Collapse
 
sidecut profile image
Jim R

Thanks! :)

The timing of your post was terrific. My boss saw it and as a result suggested we use Vue 3 on an upcoming project.

Collapse
 
gautemeekolsen profile image
Gaute Meek Olsen

Vue 3 is now in Beta! ๐Ÿฅณ