Ph0en1x
Ph0en1x

Reputation: 10067

How to enable tracking deep changes in component props

I have a component who initialized like this

<custom :opts="{map: false}"></custom>

and there is HTML similar to this

<template id="custom">
    <div v-if="opts.map">
    I'm awesome
    </div>
    <button v-on:click="show"></button>
</template>

where

function show(){
    this.opts = {map:true} // (1) <-- This is working and I could see hidden div
    this.opts.map = true // (2) <-- For some reason not working
    Vue.set(this.opts, 'map', true) // (3) <-- Still not working
}

So my question is why variant 2 doesn't work and what should I change to make my control react to value reset on a button click. Or a proper explanation why (1) is working, but (2) isn't - also will be accepted as an answer.

Upvotes: 2

Views: 749

Answers (2)

Stephen Thomas
Stephen Thomas

Reputation: 14043

The real problem with the code (all 3 versions) is changing a component's property from within a component. In idiomatic Vue, only the parent should change properties. If a component needs to effect a change, it should emit an event to the parent and let the parent make the necessary changes. Otherwise, there is ambiguity in which component "owns" the property.

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.

Sending Messages to Parents with Events

Upvotes: 1

John Smith
John Smith

Reputation: 686

Can be off base here but I believe this happens because in vue component props are not reactive, so their objects are not being observed in depth. Or rather they are "a little bit reactive", reassigning the root prop does cause the DOM update but is not expected to be done manually and you'll see a warning when doing such on development build:

[Vue warn]: 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: "..."

And for as why props are not completely reactive in the first place: https://v2.vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow

To work around the whole issue you must pass any necessary props to the component data and if those props were passed as nested objects you might also want to completely avoid mutating them from within the component since it will propagate to the parent which, unless clearly mentioned, can be a source of bad news.

Upvotes: 0

Related Questions