Vue.js communication Part 1: single component
About the series
Communication in Vue.js is one of the first topics you'll have to learn about. I came from writing Rails front-ends, mostly server-side rendered, and using a little jQuery here and there when I was starting to write Vue.js code.
When you're new to this, it might be complicated to wrap your head around this.
Components are being created separately but need to communicate together.
Outline
- Vue.js communication: single components
- Vue.js communication: parent-child components
- Vue.js communication: any component (using vuex)
Vue.js communication: single components
Single components are pretty straightforward. From my point of view, there are a handful of things you need to know to get you started. It is about how the template and script parts of a Vue component work together. Template and script form one unit and share the same data.
The best part is that you can apply some techniques in parent-child communication later!
Template to script: Events
Use events whenever you want to do something after a user event in the UI. The @click="handleClick"
part in the template will call the method handleClick
.
<template>
<button @click="handleClick">
Tacos?
</button>
</template>
<script>
export default {
name: 'SingleComponent',
methods: {
handleClick () {
alert('Tacos!')
}
}
}
</script>
v-for and events
Arguments are helpful when you're using events in a v-for
loop. When you click one of the menu entries, the event handler knows which entry has been selected.
<template>
<button
v-for="(entry, index) in menu"
:key="index"
@click="selectEntry(entry)"
>
{{ entry }}?
</button>
</template>
<script>
export default {
name: 'SingleComponent',
computed: {
menu: ['tacos', 'hot dogs', 'ice cream']
},
methods: {
selectEntry (value) {
alert(`${value} it is!`)
}
}
}
</script>
Those were a few examples. There are way more things you can do with events and handlers. The Vue.js guide explains it very well, and there are new and more advanced options now and then.
Everything about events here:
Script to template: Reactiveness
Using the reactive system is enough in most scenarios since you'll need to change data in the script part of your component, and the template renders according to the data changes.
In this example, the script changes the traffic light every 5 seconds. The template will render every time the value isGreen
changes. No need to even access the template in any way. Note that we can change the data even though the component might not be rendered by now. created
will set the interval.
To me, that's mind-blowing when you come from jQuery land. With jQuery, you must select the node and then change the text. With Vue.js, you don't need to worry.
<template>
<div class="traffic-light">
isGreen: {{ isGreen }}
</div>
</template>
<script>
export default {
name: 'TrafficLight',
data () {
return {
isGreen: false,
interval: null
}
},
created () {
this.interval = setInterval(() => {
this.isGreen = !this.isGreen
}, 5 * 1000)
},
beforeDestroy () {
clearInterval(this.interval)
}
}
</script>
Script to template: refs
In some cases, you might need a ref, even in a single component.
Two examples pop into my mind right away:
- You want to access DOMNode's attributes, e.g., canvas image data or a checkbox's checked value.
- You want to use another library and pass it the DOMNode.
Here is the canvas example.
<template>
<div id="canvas-example">
<canvas ref="canvas" height="200" width="200" />
</div>
</template>
<script>
export default {
name: 'CanvasExample',
mounted () {
const ctx = this.$refs.canvas.getContext('2d')
ctx.fillStyle = 'rgb(200,0,0)'
ctx.fillRect(10, 10, 55, 50)
ctx.fillStyle = 'rgba(0, 0, 200, 0.5)'
ctx.fillRect(30, 30, 55, 50)
}
}
</script>
Dynamic refs
I have realized this way too late, and I'm almost embarrassed. The ref will be treated like any other attribute.
That means you can also pass dynamic values.
That's handy if you have loops.
<template>
<ul id="dynamic-refs">
<li
v-for="entry in entries"
:key="entry.id"
:ref="`entry${entry.id}`"
>
{{ entry.title }}
</li>
</ul>
</template>
<script>
export default {
name: 'DynamicRefs',
data () {
return {
entries: [
{ id: 1, title: 'Uno' },
{ id: 2, title: 'Due' }
]
}
},
mounted () {
console.log(this.$refs.entry1)
}
}
</script>
v-model
When building forms, you will want the current data shown in the inputs, and the user's input saved back to the data.
The convention is:
- Pass the current data
value
into the template. - Send
input
events for user inputs.
Whenever you see value
and input
being used in a component, then: think of v-model
.
Both versions of the component behave precisely the same.
Final words
I hope you've learned something from this. Feel free to use the comments below if you need help, feel I could have covered something in more detail, or if you want to say hi!
The following article will be about parent-child component communication. This is where it becomes more interesting. We can apply what we've learned here to child components.
I'll let you know when it's ready in my newsletter. Sign up if you want to learn more.