Vue 2 props and emit - parent to child

Components communication — props and $emit

As the image:
parent to child — props
child to parent — $emit
Have you ever face some error like “don’t mutate the porps value” but sometimes not !?
We will talk about props, and assume that you already have knowledge about javascript and vuejs

Before we start -about premitive and reference type in javascript:

We all know that javascript have 5 premitive type:

  • String
  • Number
  • Boolean
  • Null
  • Undefined

the others will be reference type like “Object”

Premitive type:

When assigning value to primitive type, it will copy the value and give the new memory address.

var a = 1
var b = a // copy the value and have new address
b = 2 // change b's value
console.log(a) // 1
console.log(b) = // 2

Like the upper code. We assign a’s value to b and change b’s value will not change a’s value.
They point to different memory address.

Reference type:

When assigning value to reference type, it will copy the pointer to the address. They point to the same memory address.

var obj1 = {a: 1}
var obj2 = obj1 // copy the pointer to the address
obj2 = {a: 2} // change obj2's value
console.log(a) // {a: 2}
console.log(b) = // {a: 2}

Like the upper code. We assign a’s value to b and change b’s value will change a’s value.
They point to the same memory address.

It’s what javascript do!
We will stop talking about javascript and go into vue’s world.

Associate with vuejs props

When we pass something to component, if it’s premitive type like “String”, “Number” and you change it’s value in component. Vue will trigger the checking function to let us know that we are changing the porps value. If it’s reference type like “Object” and you change it’s value in component. Vue will not trigger the checking function. Parent and child will share the value, point to the same address. They will change at the same time.

About passing premitive type object to child

It’s convenient, right. But, it will hard to debug. you can add anything any type everything you want in object. It will destory what vue design => one way flow, and can’t change father’s data. Obviously, a good framework must have some rule but vue doesn’t force you to do this. You can still pass object to child. There are many vue form table generater pass object or array to the component.

The correct way to use props and $emit

OK, so what’s correct way ? we want component reusable, it should pure. Following is the flow what vue design.

  1. Parent has data to control, pass data to child component by props.
  2. If child component need to deal with props data, assign props data value to itself’s data when component mounted.
  3. After handle method, parent open a interface to child. Child $emit back new value to parent.
  • (every component has it scope and data.)

Example:

  • In parent component:
// html
<div id="counter-event-example">
<child-component
:parentData="parentData"
@interface="handleFcAfterDateBack">
</child-component>
<child-component
:parentData="parentData"
@interface="handleFcAfterDateBack">
</child-component>
</div>
// js
data () {
parentData: 'init data'
},
method () {
handleFcAfterDateBack (event) {
console.log('data after child handle: ', event) // get the data after child dealing
}
}

If you don’t need to handle after dealing just wanna data’s new value, you can do it like this (without write a method in parent)

// html
<div id="counter-event-example">
<child-component
:parentData="parentData"
@interface="handleFcAfterDateBack">
</child-component>
<child-component
:parentData="parentData"
@interface="parentData = $event">
</child-component>
</div>
  • In child component
// js
data: function () {
return {
childData: ''
}
},
props: {
parentData: {
type: String,
default () {
return ''
}
}
},
methods: {
// maybe onchagne may onclick whatever..
handleDataFc: function () {
this.$emit('interface', this.childData) // handle data and give it back to parent by interface
}
},
beforeMount () {
this.childData = this.parentData // save props data to itself's data and deal with it
}

You can also use computed without setting data in child.

If we want to commuicate to parent’s parent or more… or the data is sharing. You should use vuex.

Last:

Let’s take a look at what official saying:

One-Way Data Flow

All props form a one-way-down binding between the child property and the parent one: when the parent property updates, it will flow down to the child, but not the other way around. This prevents child components from accidentally mutating the parent’s state, which can make your app’s data flow harder to reason about.

In addition, every time the parent component is updated, all props in the child component will be refreshed with the latest value. This means you should not attempt to mutate a prop inside a child component. If you do, Vue will warn you in the console.

Note:

Objects and arrays in JavaScript are passed by reference, so if the prop is an array or object, mutating the object or array itself inside the child will affect parent state.

Thanks!