Hopp til hovedinnhold

An introduction to Vue 3 from a React developer.

Vue.js is a popular JavaScript framework. With over 2 million weekly downloads (at the time this article was written), and with 191k stars on Github, it is safe to say that it's widely used. Vue is a progressive framework, meaning it adds additional markup to HTML.

The Vue.js framework is versatile, applicable to both single page applications as well as more complex apps. It seems like a great framework, let's dig a little deeper!

Vue vs. React

React and Vue was released almost at the same time, React had its initial release in 2013 while Vue was released in 2014. Both is open sourced, has a Virtual DOM and is component based. But how do you know which technology to use?

Luckily, some clever people in the JavaScript community has over the years created State of JS (creds to Sacha Greif and Raphaël Benitte for creating this), comparing the different frameworks.

React has been the top choice for several years since this great website started. According to State of JS, it was surpassed by Vue in 2018 in the satisfaction category. Based on usage, React is the most popular framework every year. Vue was the framework most developers were interested in trying in 2018, but was surpassed by Svelte in 2019 and 2020. For more comparisons of the JavaScript frameworks, you can checkout the State of JS survey below 👇

Vue 2 vs. Vue 3

Vue has existed for some time now, and like every other framework, it has gone through some changes over the years. In this article I will focus on the Vue 3, which was released in September 2020. Still, I think it's a good idea to look at some history, so let's look at the differences between Vue 2 and Vue 3.

Vue 3 introduced (a lot of) changes to the API. It went from the so called Options API to the Composition API. The main goal for this change was for code sharing (code reuse?). In the early version of Vue, the JavaScript code was split into different functions, making it hard to reuse components through your application. Look at the code example for Vue 2 Composition API:

export default {
  data() {
    return {
      name: 'Bekk Christmas',
    };
  },
  methods: {
    greet() {
      console.log(`Hello ${this.name}`);
    },
  },
  mounted() {
    this.greet();
  },
};

In Vue 3 they created a more dynamic way for handling the data for a component, by implementing the Composition API:

export default {
  setup() {
    const name = ref('Bekk Christmas');
    
    const greet = () => console.log(`Hello ${name.value}`);
    
    onMounted(() => {
      greet();
    });
    
    return { name };
  },
};

By using the setup function, we can group the code according to what makes sense logically.

For more information about the Options API and the Composition API, check out the link below!

Let's look at some more Vue code!

For the next paragraphs I will show some basic examples for typically elements you'll want to use in a Vue component.

Hello World

Let's start with the basics; how a Vue file is structured. A single file component in Vue has a <template> and a <script> tag, where the template is where you write your markup and script is where you define your component writing JavaScript. Look at the template of a Vue component in the code below:

<template>
    // HTML code
</template>

<script>
    // JavaScript
</script>

As mentioned earlier in this article, Vue 3 has the setup() function. This function is more suitable for reusing code in your component. The data you return in your setup function will be available in your template, both variables and functions.

<template>
    <h1>{{ title }}</h1>
</template>

<script>
    export default {
        setup() {
            return {
                title: 'Hello, Bekk Christmas',
            }
        } 
    }
</script>

Reactive references

If you are familiar with React, you may have used the useEffect hooks, Vue has a similar function, only you use ref to get a reactive reference.

import { ref, watch } from 'vue'

export default {
    setup() {
        const name = ref('Bekk Christmas')
    }  
}

A reactive reference make sure that the view updates whenever the value of the reactive reference changes.

Conditional rendering

Sometimes (I dare to say always) we want to show some data based on the state of your application, and in other cases we want to hide it. Vue has a series of directives you can use in your template, the directives are Vue specific HTML attributes that allow you to manipulate the DOM.

To conditionally render your data, you can use the v-if directive.

<div v-if="name.length">
    <p>{{ name }}</p>
</div>

It is possible to use v-if-else and v-else for conditional rendering. Here are an overview of the different directives you can use in Vue.

List iterator

As a developer, I don't want to do more work than necessary. I want an easy way to iterate over lists. As mentioned in the section above, Vue has some directives we can use. To iterate over a list in Vue, you can use the v-for directive which is written as "item in items" as input. This is different from the way we iterate over lists in React where you use the .map function. Let's look at a classic <li> example:

<ul>
    <li v-for="(item, index) in items" :key="item.id">
        {{ item.text }}
    </li>
</ul>

In the example above you'll see the :key property. It is a shorthand for the v-bind directive (written as v-bind:key="item.id"). It binds attributes or a prop to an expression. In the example above, the key is bound to item.id to get a unique identifier so Vue knows which list item to update. This is similar to the key prop in React.

Input and two-way bindings

I know what you are thinking, what is an application without a form with a binding to some data we can update? The classic example is having an input field, and a preview of the data passed into it. Look at the code example below:

<template>
    <input type="text" placeholder="Add item" v-model="newItem" />
    <button @click="addItem">
        Add Joke
    </button>
</template>

In this example @click on the button is a shorthand for v-on:click. The v-on directive attaches an event listener (in this case my addItem function) to the button. In addition, if you look at the input tag, I have added a v-model, this directive creates a two-way binding on an input field to the newItem data. Let's look at the JavaScript to fully understand the connection to the data.

<script>
    export default {
        setup() {
            const newItem = ref('')
            const items = ref([])

            const addItem = function() {
                items.value.push({
                    newItem
                })
            }

            return {
                addItem,
                newItem
            }
        }
    }
</script>

Look at the newItem variable and addItem function. To fully connect the input field you need to connect the addItem function to the button which updates newItem variable, and add newItem to the v-model for the input field to display the updated value.

Watch for changes

When using a variable in Vue, we sometimes want to update it based on changes in another variable. Let say you have a list of items, and in your view you want to display the number of items. Declaring the variables is shown in the code example below:

const items = ref([])
const numberOfItems = ref(items.value.length)

There's one problem with the example above. On initial render the numberOfItems value will be correct, but if we are updating the items list, the numberOfItems will not update correctly. If you are familiar with React, you may have used the useEffect hook. There is a similar way to watch for changes in Vue, only it is done by using the watch function.

import { watch } from 'vue'

watch(items.value, () => {
    numberOfItems.value = items.value.length
})

The watch function takes the data it should be watching as first argument, and a callback as the second argument which is applied when the data you are watching has changed. This way the numberOfItems will update whenever items has changed.

Child Components

Let's look at how to use components in components! In larger application it is not sufficient to have only one component, so component compositions is a nice way to split your code. To use a child component you need to register the component. Look at the example of a parent component below:

<script>
    export default {
        components: {
            MyButton,
        },
        setup() {
            ...
        }
    }
</script>

You can use the MyButton component in another component by writing JSX <MyButton /> (as in React) or accept the magic that Vue does and write <my-button /> in your template. If you want to render any JSX between the start and end tag of your parent component, you need to use <slot /> in your child component (it's not called 'children' as it is in React).

In the next code example you can see the child component. It gets some props from the parent, like childClass and onButtonClick, and renders slots.

<template>
    <button :class="childClass" @click="onButtonClick">
        <slot />
    </button>
</template>

When passing event listeners to components, you can trigger it by emitting the desired function you sent in as props. The $emit in the onButtonClick function defines events that the child component can send (or emit) to the parent.

Every front end framework which have component composition need to have a way to define props (yes, I said it). You can define your props with an array of strings (e.g. props: ['title', 'childClass']) or as in the code example where you can define the specific type (TypeScript <3). Look at the JavaScript for the child component:

<script>
    export default {
        props: {
            childClass: String,
        },
        setup() {
            const onButtonClick = function() {
                this.$emit('my-click')
            }

            return {
                onButtonClick
            }
        }
    }
</script>

There are also two ways to pass props, either static or dynamic. Example of static types is <MyComponent value="42" />, and dynamic props is where you use v-bind and connect it with data, example <MyComponent :value="item.answer" />.

That's it folks

I really enjoyed learning Vue, and I think it is a great framework to use in your next project. I think it is good to know what is out there in the world of JavaScript frameworks, and not be stuck in some old React pattern with class components and componentShouldUpdate. ... Even though I really, really like React!

Hope you liked this post about Vue!

Relevant resources recommended by the author

Did you like the post?

Feel free to share it with friends and colleagues