The two core properties of a Vue instance are data and methods. These properties are the backbone of any Vue application and play a crucial role in creating dynamic and reactive user interfaces. Data stores the state of your application, and methods allow us to modify the state. Although these properties are part of Options API (a Vue 2 feature), you may still encounter them in the Vue 3 version.
Let's learn about each property in more detail and see how they work together.
Understanding data
Before diving deep into the topic, let's create a Vue instance inside our main.js file:
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')The file above is the entry point of our app, usually kept clean and small, and the remaining code is split into components. The App component is where we'll write our main code, so let's head over to it.
In Vue.js, the data property is used to store the state of the application. It is a function that returns an object. The object's properties are the values we can access from the template and modify. The data property is defined inside the script tag as follows:
// src/App.vue
<script>
export default {
data() {
return {
name: 'Sarah',
lang: 'JS'
}
}
}
</script>We have two variables in our state, name and lang. Time to render some HTML: let's add a template inside the same App.vue file:
// src/App.vue
<template>
<div>Hi, I'm {{ name }} and I'm learning {{ lang }}!</div>
</template>If you start the app and check it in the browser, you should see the following:
Hi, I'm Sarah and I'm learning JS!Remember always to include state variables inside double curly braces, as we did with name and lang. Now write your name instead of "Sarah" and see what will happen on the page. Cool, this is how reactive Vue.js is.
Manually changing the state is fine, but this is not what you'll see in real-life apps. Usually, we need some functions to trigger when we want to modify the state.
Understanding methods
The methods property is an object that contains all the functions we want to use in a component. For example, we can store functions that will change our state, print something to the console, alert a message, or do other more complex operations. This is how we can declare the methods:
// src/App.vue
<script>
export default {
data() {
return {
name: 'Sarah',
lang: 'JS'
}
},
methods: {
upgrade() {
this.lang = 'Vue.js'
},
downgrade() {
this.lang = 'JS'
}
}
}
</script>As you can see, we added the upgrade function that sets a new value for the lang property, and the downgrade function that reverts the state to the original value, which is 'JS'. By the way, if we wanted to write more functions, we would place them all inside the methods property and separate them with a comma. You can try adding a third function on your own, such as a simple alert.
Connecting methods with the template
For now, our upgrade and downgrade functions don't do anything, so we need to find a way to link them up with our template. Inside the template, let's create two simple button elements. In vanilla JS, we would use an onclick event. Fortunately, it's pretty similar in Vue.js: instead of onclick we use the v-on: directive and specify what event we're listening for. If you're using VS Code, you can type v-on:, and it will list all available events. We need the onclick event, so let's write v-on:click. Then we specify which method we want to trigger with each button:
// src/App.vue
<template>
<div>Hi, I'm {{ name }} and I learn {{ lang }}</div>
<button v-on:click="upgrade">Upgrade!</button>
<button v-on:click="downgrade">Downgrade</button>
</template>If you check your browser and click the buttons, you will see that the lang value changes dynamically:
By the way, instead of v-on:click, you can use a shortcut @click that will do the same thing.
There are a couple more directives like v-on: you might want to take a quick look at the Vue.js Docs.
Let's do one more challenge. Let's create a function that outputs the name of the language creator. In our case, it's either Evan You (Vue) or Brendan Eich (JS). Here's our showAuthor() method:
// src/App.vue
<script>
export default {
data() {
return {
name: 'Sarah',
lang: 'JS'
}
},
methods: {
upgrade() {
this.lang = 'Vue.js'
},
downgrade() {
this.lang = 'JS'
},
showAuthor() {
let author = 'Brendan Eich'
if (this.lang === 'Vue.js') {
author = 'Evan You'
}
return author
}
}
}
</script>We start with Brendan Eich since JS is the initial lang we set. Then we check if the lang equals Vue.js, and we change the author as well. Finally, the function returns the author variable.
In the template, create a new div and call the function using double curly braces:
// src/App.vue
<template>
<div>Hi, I'm {{ name }} and I learn {{ lang }}</div>
<div>{{ lang }} was created by {{ showAuthor() }}</div>
<button @click="upgrade">Upgrade!</button>
<button @click="downgrade">Downgrade </button>
</template>Check it out in the browser — the values should change dynamically:
Great! We've just created a simple reactive Vue.js app. If you'd like to change the styles, feel free to do so. You can include them in the <style></style> tag below the template and you should be good to go!
Data and methods in Vue 3
Vue 3 has a slightly different approach. In Composition API you'll declare data and methods via setup() hook. Look at this example:
Using the
setup()hook:
// src/App.vue
<script>
import { ref } from 'vue';
export default {
setup() {
const name = ref('Sarah')
const lang = ref('JS')
const upgrade = () => {
lang.value = 'Vue.js'
}
const downgrade = () => {
lang.value = 'JS'
}
const showAuthor = () => {
let author = 'Brendan Eich'
if (lang.value === 'Vue.js') {
author = 'Evan You'
}
return author
}
return { name, lang, upgrade, downgrade, showAuthor }
}
}
</script>Inside
setup(), we declare our variables and functions.The reactive values (the ones that will change) must be wrapped with the
reffunction. If we don't do this, our state won't mutate and won't be dynamic as we wanted.Every variable that was wrapped with
reffunction should be accessed viavariable.value.After we specify all variables and functions, we need to return them. This return will make our variables available within the template, so we can access them using
{{}}.
You can use the same template from the previous section and see that the results are the same.
If you're wondering if there's a more elegant way, it exists — just keep reading.
Using
<script setup>:
// src/App.vue
<script setup>
import { ref } from 'vue';
const name = ref('Sarah')
const lang = ref('JS')
const upgrade = () => {
lang.value = 'Vue.js'
}
const downgrade = () => {
lang.value = 'JS'
}
const showAuthor = () => {
let author = 'Brendan Eich'
if (lang.value === 'Vue.js') {
author = 'Evan You'
}
return author
}
</script>The key difference in this code is that you no longer need the setup() hook if you specify it within the script tag. Also, no return statement — the variables can be accessed in the template without it.
As you can see, Composition API provides an easier and more convenient way of handling data and methods. The code becomes more readable and scalable. With Composition API you can reuse the same logic across multiple components instead of duplicating the same data property in different places of the app.
Conclusion
In this topic, we discussed the essential concepts in Vue.js — data and methods. The former sets the local state, whereas the latter lets us define custom methods that we can use to provide reactive behavior on the page. To access the local state variables inside the template, we use double curly braces. The methods can be triggered via the v-on: directive. In Vue 3, however, all logic is encompassed within the setup() hook, and the ref function makes the reactivity possible.