In this tutorial, I’ll take you through how you can pass data between VueJs different components through listening to properties changes.
Data can easily be passed from the parent to the child by using “Props” or “$attrs”. Therefore, down the hierarchy, you don’t have to do anything “props” will be inherently reactive. This is known as “Data Down”.
Then you can access your Prop
the same way you access your other Data properties, here is an example:
Vue.component('blog-title', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})
after defining your Prop you will be able to pass it to the child component like this:
<child-title title="My Vue Title"></child-title>
Visit Vue’s official website for more about Passing-Data-to-Child-Components-with-Props, but to pass data from the child to the parent are not alike, this is to avoid a collision, and most of the devs don’t need to use it since it’s an anti-pattern, that’s why you might probably get a warning.
Passing data to the Parent: "Known as "Action Up"
1-Emitting an Event (recommended for most frameworks):
→ The goal here is to pass Data from the Child component to the Parent (by triggering an event or watching your Prop).
as most developers suggest. you’ll find that this is the cleanest way to do it, emit an event from the Child component.
where data-Down refers to passing data from the parent to the child by using “Props”, and Action-Up means that you trigger an action in the child that the parent is listening to (e.g: click).
let’s see this example right here:
this is the child component:
The child component can emit an event on itself by calling the built-in $emit
, passing the name of the event to be triggered:
<button v-on:click="$emit('changeSomething')">Click me</button>
as you can see in the child component we Listen to the Click event, triggering it calls for the changeSomething method which is called in the Parent component.
this is the parent component:
<child-component
...
v-on:changeSomething="title = 'New title' "
></child-component>
note: title = 'New title'
can be replaced by a method.
e.g:
changeTitle(){
this.title = 'New title'
}
Now let’s emit a specific value with the event.
<button v-on:click="$emit('changeSomething', "new title")"></button>
when we listen to the event in the parent, we can access the emitted event’s value with the built-in $event
:
<child-component
...
v-on:changeSomething="title = $event"
></child-component>
Or as a method:
v-on:changeSomething="changeTitle"
in this case, the value “$event” will be passed as a parameter to the function
methods: {
changeTitle: function (value) {
this.title+= value //vlue will the new title passed as parameter.
}
}
2- Watch Proprities and Update them once they’ve change:
Type: {[key: string]: string | Function | Object | Array}
As the name suggest Watch:{}
is an Object used to watch your priorities and then you can choose to act accordingly.
watch principal:
var vm = new Vue({
data: {
a: 1,
},
watch: {
a: function (newVal, oldVal) {
console.log('new: %s, old: %s', newVal, oldVal)
},
newVal candidates the current value of a whereas oldVal indicates the last value a has held, this only indicates that using watch you can keep track of your data and handle them.
common method:
→ In this case, it’s recommended you use the immediate property
watch: {
myProp: {
// the callback will be called immediately after the start of the observation
immediate: true,
handler (val, oldVal) {
// do your stuff
}
}
}
track all prop changes:
this will be useful to avoid making seperated watcher for all your props,
watch: {
$props: {
handler() {
this.parseData();
},
deep: true, // used to keep track on not only your props but it's nested values like as well e.g. `props.myProp`
immediate: true,
},
Stop watching:
To tear down the watcher, you can use unwatch()
that stops firing the callback.
3-The “two-way binding” (not recommended):
.sync
Modifier - (2.3.0+) a syntax sugar that expands into a v-on
handler for updating the bound value.
This is a New easy way for the “two-way binding” for a prop *produced in Vue 2.3.0
you got to be careful since two-way binding can cause maintenance issues because child components can mutate the parent without the source of that mutation being obvious in both the parent and the child. That’s why it most recommended to Emit an event.
If myProp is changed in child component it won’t be reflected in the parent component. You have to use .sync
modifier in the parent, then you can either emit an event from the child component just like we did previously,
or watch the prop in the child component.
Parent.vue
<template>
<div>
<child :myProp.sync="myProp"></child>
<input v-model="myProp"/>
<p>{{myProp}}</p>
</div>
</template>
<script>
import child from './Child.vue'
export default{
data(){
return{
myProp:"hello"
}
},
components:{
child
}
}
</script>
<style scoped>
</style>
Child.vue
<template>
<div> <grand-child :myProp.sync="myProp"></grand-child>
<p>{{myProp}}</p>
</div>
</template>
<script>
import grandChild from './Grandchild.vue'
export default{
components:{
grandChild
},
props:['myProp'],
watch:{
'myProp'(){
this.$emit('update:myProp',this.myProp)
}
}
}
</script>
<style>
</style>
note: .sync
modifier does not work with expressions.
(e.g. v-bind:title.sync = ” title + '?' ”
) is invalid.
4- Vuex:
Props and don’t work when you have two sibling components (child of the same root), meaning communication between these two is impossible.
That’s why Vue has introduced Vuex.
Vuex is a state management pattern + library for Vue.js applications.
Vuex takes all shared state out of the components and manages it in a global singleton (join them in a single source of truth).
Using Vuex, any component will be able to access the state or trigger actions, no matter where they are in the tree.