Passing data to Child Component - Props
Vue provides 'Props' (Properties) to define custom HTML attributes.
Ex:
// Parent: html
// Child: script
NOTE: We need to use 'lower camel case' for props in JavaScript, and use 'kebab-case' in html. (Refer to this)
According to 'One-Way Data Flow', you cannot mutate props.
If you change it, you will see below errors.
error Unexpected mutation of "xxx" prop vue/no-mutating-props
There are two ways to let you change the value binding to child components:
// Parent: html
<welcome-message
header="My Header"
message="Hello World!"
></welcome-message>
<script>
export default {
props: ["header", "message"],
};
</script>
NOTE: We need to use 'lower camel case' for props in JavaScript, and use 'kebab-case' in html. (Refer to this)
Can we change Props?
If you change it, you will see below errors.
error Unexpected mutation of "xxx" prop vue/no-mutating-props
There are two ways to let you change the value binding to child components:
1. A child component emits a custom event to its parent component, and the parent component change the props value based on data data from the custom event.
2. Take props as init value of local data properties of the child component. Then, we can change the value of those local properties.
Props Type and Validators?
Ex:
props: ["name", "phoneNumber", "email"],
Vue provides an object format to let you define the detail information of each props.
Ex:
props: {
name: String,
phoneNumber: {
type: String,
required: false,
default: '11234567890'
},
email: {
type: String,
required: true,
validator: function(value) {
return value.includes('@');
}
}
}
Examples of validating failed:
Invalid prop: custom validator check failed for prop "email".
Invalid prop: type check failed for prop "email". Expected String with value "undefined", got Undefined
Set Props dynamically?
However, we can use what we have learned before such as v-bind to dynamically bind the value to those custom html attributes.
Ex:
<welcome-message
v-bind:header="header"
v-bind:message="message"
></welcome-message>
Passing data to Parent Component (Emitting a custom event)
Then it can react in actions if something happened.
Ex:
// Child script
onUpdateButtonClicked() {
this.$emit("message-update", this.message);
}
<welcome-message
v-bind:header="header"
v-bind:message="message"
v-on:message-update="updateMessage"
></welcome-message>
updateMessage(message) {
this.message = message;
},
Define custom events explicitly
Below is the basic version to help other developers can easily know what events belongs to this components instead of tracking the code.
Ex:
emits: ["message-update"],
Vue also provides a rich information version.
Ex:
emits: {
"message-update": function (message) {
if (message) {
return true;
}
return false;
},
},
Provide and Inject
There is an example below.
// Structure
├───App.vue
│ ├───ParentComponent.vue
│ │ ├───ChildComponent.vue
// App.vue
<template>
<div>
<section>
<h1>{{ message }}</h1>
</section>
<section>
<parent-component
v-bind:message="message"
v-on:update-message="updateMessage"
>
</parent-component>
</section>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello World!',
};
},
methods: {
updateMessage(message) {
this.message = message;
},
},
};
</script>
// ParentComponent.vue
<template>
<child-component
v-bind:message="message"
v-on:update-message="$emit('update-message', $event)"
>
</child-component>
</template>
<script>
export default {
props: ['message'],
emits: ['update-message'],
};
</script>
// ChildComponent.vue
<template>
<form>
<input type="string" v-model="enteredValue" />
<button v-on:click.prevent="$emit('update-message', enteredValue)">
Update Message
</button>
</form>
</template>
<script>
export default {
props: ['message'],
emits: ['update-message'],
data() {
return {
enteredValue: this.message,
};
},
};
</script>
You can notice that 'ParentComponent.vue' will just pass props to 'ChildCompoennt.vue', and pass custom event to 'App.vue'.
If data need to be passed through multiple components, you can use 'Provide and Inject' pattern.
Provide and Inject with Props
// App.vue
<template>
<div>
<section>
<h1>{{ message }}</h1>
</section>
<section>
<parent-component v-on:update-message="updateMessage">
</parent-component>
</section>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello World!',
};
},
provide() {
return { message: this.message };
},
methods: {
updateMessage(message) {
this.message = message;
},
},
};
</script>
// ParentComponent.vue
<template>
<child-component v-on:update-message="$emit('update-message', $event)">
</child-component>
</template>
<script>
export default {
emits: ['update-message'],
};
</script>
// ChildComponent.vue
<template>
<form>
<input type="string" v-model="enteredValue" />
<button v-on:click.prevent="$emit('update-message', enteredValue)">
Update Message
</button>
</form>
</template>
<script>
export default {
inject: ['message'],
emits: ['update-message'],
data() {
return {
enteredValue: this.message,
};
},
};
</script>
Provide and Inject with Methods
Can we use the same approach for methods?
// App.vue
<template>
<form>
<input type="string" v-model="enteredValue" />
<button v-on:click.prevent="$emit('update-message', enteredValue)">
Update Message
</button>
</form>
</template>
<script>
export default {
inject: ['message'],
emits: ['update-message'],
data() {
return {
enteredValue: this.message,
};
},
};
</script>
// ParentComponent.vue
<template>
<child-component></child-component>
</template>
<script>
export default {};
</script>
// ChildComponent.vue
<template>
<form>
<input type="string" v-model="enteredValue" />
<button v-on:click.prevent="updateMessage(enteredValue)">
Update Message
</button>
</form>
</template>
<script>
export default {
inject: ['message', 'updateMessage'],
data() {
return {
enteredValue: this.message,
};
},
};
</script>
Provide and Inject V.S. Props and Custom Events
We will use 'Provide and Inject' only to deal with passing data through multiple components.
Otherwise, we need to stick with 'Props and Custom Events' because it will reduce readability when using 'Provide and Inject' approach.
No comments:
Post a Comment