I'm a bit confused about how to change properties inside components, let's say I have the following component:
{
props: {
visible: {
type: Boolean,
default: true
}
},
methods: {
hide() {
this.visible = false;
}
}
}
Although it works, it would give the following warning:
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "visible" (found in component )
Now I'm wondering what the best way to handle this is, obviously the visible
property is passed in when created the component in the DOM: <Foo :visible="false"></Foo>
The value of a parent property cannot be changed inside a component, and, in fact, the updated value will be lost if the parent re-renders for any reason. To update the parent property, what you should do is $emit the updated value and listen for the change in the parent.
The changed prop is not used by the render function so rendering should not be triggered. There are several use cases for props that don't require rendering updates. e.g.: The prop could be an id used to load data behind the scenes.
To access props in a Vue. js component data function, we can get them from this . to register the messageId prop. Then we get the initial value of the messageId prop with this.
Referencing the code in your fiddle
Somehow, you should decide on one place for the state to live, not two. I don't know whether it's more appropriate to have it just in the Alert
or just in it's parent for your use case, but you should pick one.
Does the parent or any sibling component depend on the state?
In some rare cases, you may want a combination. Perhaps you want to give both parent and child the ability to hide the child. Then you should have state in both parent and child (so you don't have to edit the child's props inside child).
For example, child can be visible if: visible && state_visible
, where visible
comes from props and reflects a value in the parent's state, and state_visible
is from the child's state.
I'm not sure if this is the behavour that you want, but here is a snippet. I would kinda assume you actually want to just call the toggleAlert
of the parent component when you click on the child.
var Alert = Vue.component('alert', { template: ` <div class="alert" v-if="visible && state_visible"> Alert<br> <span v-on:click="close">Close me</span> </div>`, props: { visible: { required: true, type: Boolean, default: false } }, data: function() { return { state_visible: true }; }, methods: { close() { console.log('Clock this'); this.state_visible = false; } } }); var demo = new Vue({ el: '#demo', components: { 'alert': Alert }, data: { hasAlerts: false }, methods: { toggleAlert() { this.hasAlerts = !this.hasAlerts } } })
.alert { background-color: #ff0000; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <div id="demo" v-cloak> <alert :visible="hasAlerts"></alert> <span v-on:click="toggleAlert">Toggle alerts</span> </div>
According to the Vue.js component doc:
When the parent property updates, it will flow down to the child, but not the other way around. So, how do we communicate back to the parent when something happens? This is where Vue’s custom event system comes in.
Use $emit('my-event)
from the child to send an event to the parent. Receive the event on the child declaration inside the parent with v-on:my-event
(or @my-event
).
Working example:
// child
Vue.component('child', {
template: '<div><p>Child</p> <button @click="hide">Hide</button></div>',
methods: {
hide () {
this.$emit('child-hide-event')
}
},
})
// parent
new Vue({
el: '#app',
data: {
childVisible: true
},
methods: {
childHide () {
this.childVisible = false
},
childShow () {
this.childVisible = true
}
}
})
.box {
border: solid 1px grey;
padding: 16px;
}
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<div id="app" class="box">
<p>Parent | childVisible: {{ childVisible }}</p>
<button @click="childHide">Hide</button>
<button @click="childShow">Show</button>
<p> </p>
<child @child-hide-event="childHide" v-if="childVisible" class="box"></child>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With