Both the parent and child should have the data/props declared independently from one another. The idea is that you are separating the concerns of each component. Only the component knows what it actually needs. If you remove or add properties to child or parent, both implementations change since they are directly coupled by data/props. By declaring in both, changing one doesn't immediately break the API of both components.
Additionally, mutating props that are injected into a component directly is considered an anti-pattern for a few reasons. Consider this from the documentation Prop Mutation:
Mutating a prop locally is now considered an anti-pattern, e.g.
declaring a prop and then setting this.myProp = 'someOtherValue'
in
the component. Due to the new rendering mechanism, whenever the parent
component re-renders, the child component’s local changes will be
overwritten.
One of Vue's mantras is "props down, events up". Events don't care about parental implementation, they fire regardless of whether or not the parent is listening. This further eases the case where the data of a parent changes because you, again, don't have to change the props of a child to prevent API breakage.
In your example, the child dialog that has the <button>
shouldn't set whether the dialog is visible or not directly. It should propagate up an event to the parent component and tell the parent "The close button was clicked, consider that as you will." The parent should then make the decision to set the dialog
prop to false
or not.
Here's an example where the dialog component emits a "close" event and doesn't need to take in a prop at all:
Vue.component('my-dialog', {
template: `
<div>
<p>Worlds smallest dialog</p>
<button @click="$emit('close')">
Close Dialog
</button>
</div>
`
})
new Vue({
el: '#app',
data() {
return { dialog: false }
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<button @click="dialog = true">Show Dialog</button>
<my-dialog v-show="dialog" @close="dialog = false">
</my-dialog>
</div>