September 25, 2020

hosein

Articles Tutorials

Vue 3: Top 5 New Features

After Months of being in beta stage Vue v3 stable version is finally released, because of that let’s see what differences does this new version make and why vue is now an even better framework than before.

while in version 3 the whole framework was written from scratch, the syntax didn’t change which is remarkable and other than that and some other changes vue 3 introduces some interesting new features

5- Better typescript support

Typescript has become more and more popular in the past few years, specially among teams but vue 2 didn’t support all of typescript features. vue 3 was completely created using typescript and not only it fixes some problems with typescript, it fully supports typescript in it’s core

4- Multiple component root elements

In previous versions of vue you couldn’t have multiple html elements in component’s root <template /> (just like react before adding fragments) which was sometimes annoying but in vue 3 you can have as many as elements as you want in the component’s root:

<!-- this won't throw an error anymore! -->
<template>
  <Sidebar />
  <Main />
</template>

while you had to wrap the elements in a div or something in version 2 and before

3- Suspense

Most apps need to send requests to an api and receive data asynchronously and that most times isn’t instant so we have to show a loading or something to the user until the data is loaded, in vue 2 you had to use the v-if and v-else directives and a loading data to show a loading component before the required data is loaded.

but vue 3 introduces a new component called suspense (react has a similar feature too with the same name but it’s still experimental) and it accepts two components for default and loading states, and you don’t have to handle that manually with data anymore:

<Suspense>
    <template #default>
      <Items v-for="item in list" :key="item.id">
        {{ item.title }}
      </Item>
    </template>
    <template #fallback>
      <Spinner />
    </template>
</Suspense>

To do the same thing in vue 2:

.
.
.
<div class="items">
    <template v-if="!loading">
      <Items v-for="item in list" :key="item.id">
        {{ item.title }}
      </Item>
    </template>
    <Spinner v-else />
</div>
.
.
.
data(){
 return{
  loading: false,
  list: []
 },
 created(){
  this.loading = true
  const list = axios
      .get('https://api.com/list')
      .then(response => {
        this.loading = false
        this.list = response.data
      }).catch(error=>{
       this.loading = false
      })
 }
}

2- Teleport

trust me teleport is as cool as the name suggests! so there are some cases where you need to render a component in a different DOM element, for example you want to have a modal or a fixed element or something in the body element, before vue 3 we had to do this with a third party library but this feature is built in the framework with the Teleport global component:

<div class="somewhere-deep-in-dom">
 <!-- to: the element's unique tag, class or id -->
 <Teleport to="body">
  <Modal v-model="showModal" />
 </Teleport>
</div>
.
.
.

1- Composition API

In vue js components you had to follow a particular syntax called options api to declare the component’s props, data, methods, watch, computed, etc in separate objects:

<script>
export default {
  data() {
    return {
     list: []
    }
  },
  computed: {
    reversedList() {
      return this.list.reverse()
    }
  },
  watch: {
    list(newVal) {
      console.log('list updated', newVal)
    },
  },
  methods: {
     add(name) {
      this.list.push(name)
    },
  }
 
}
</script>

this usually is okay, but in big and complex components this syntax becomes annoying as you have to do a lot of scrolling and the component’s logic is scattered in different places

while you can still use options api, version 3 introduces an alternative syntax called composition api, with composition api you can have data, methods, computed and watch in the same place in the new setup() life cycle hook which runs before the component is mounted, the below example shows how you can use this new api:

<script>
// ref,computed and watch methods are used instead of objects
import { ref, computed, watch } from 'vue'
export default {
  setup(props) {
    // you can define data with 'ref' and 'reactive' methods
    let list = ref([])
    // simply define methods as functions, just like react
    // note that to access 'ref' data you have to refer to it's 'value' (but not in template) and you no longer have to write 'this'
    const add = (name)=> {
      list.value.push(name)
    },
    // define computed properties with the 'computed' method
    const reversedList = computed(() => list.value.reversed())
   // watch data with 'watch' method
    watch(list, newVal => {
      console.log('list updated', newVal)
    })
    
    // lastly return all data,methods and computeds
    return {
      list,
      add,
      reversedList
    }
  }
}
</script>

If you have worked with react you are familiar with custom hooks to extract logic and reactive data and import it somewhere else, in vue 2 your only option was mixins but in vue 3 you can have something similar to hooks thanks to composition api:

// hooks/useCounter.js
import { ref, computed } from 'vue'

export default function () {
  const count = ref(0)
  function increment() {
    count.value++
  }
  function decrement() {
    count.value--
  }
  return {
    count,
    increment,
    decrement
  }
}

and we can import useCounter in any component’s setup():

<script>
import useCounter from '../hooks/useCounter.js'
export default {
  setup() {
    const { count, increment, decrement } = useCounter()
    // these will be accessible from template  
    return {
      count,
      increment,
      decrement
    }
  }
}
</script>

other than these features vue 3 has added some other features and changes, you can see the full list here