Vue.js Change props

I am a bit confused about how to change properties inside components, say I have the following component:

{ props: { visible: { type: Boolean, default: true } }, methods: { hide() { this.visible = false; } } } 

Although it works, it will issue the following warning:

Avoid muting the prop directly, as the value will be overwritten whenever the parent component re-displays. Instead, use data or a computed property based on the value of prop. Prop mutated: "visible" (found in component)

Now I'm wondering how best to deal with this, it is obvious that the visible property is passed when the component is created in the DOM: <Foo :visible="false"></Foo>

+6
source share
5 answers

Link to the code in your violin

Somehow, you should choose one place for the life of the state, and not two. I don’t know if it was more appropriate to have it only in Alert or just parent in it for your use case, but you should select it.

How to decide where life is

Does the parent or any component of the marriage depend on the state?

  • Yes: then it should be in the parent (or in some external state management)
  • No: then it's easier to have it in the state of the component itself
  • Kind: see below

In some rare cases, you may need a combination. Perhaps you want to give parents and the child the opportunity to hide the child. Then you must have state in both the parent and the child (so you do not need to edit the child details inside the child).

For example, a child may be visible if: visible && state_visible , where visible comes from the visible && state_visible and reflects the value in the parent state, and state_visible from the child state.

I'm not sure if this is what you need, but here is the fiddle . I would suggest that you really want to just call the toggleAlert parent component when you click on the child.

+8
source

After reading your last comments, it seems you are worried about having logic to show / hide parent warnings. Therefore, I would suggest the following:

parent

 # template <alert :alert-visible="alertVisible"></alert> # script data () { alertVisible: false, ... }, ... 

Then, in the child warning, you will look at the value of prop and move all the logic to the warning:

child (warning)

 # script data: { visible: false, ... }, methods: { hide () { this.visible = false }, show () { this.visible = true }, ... }, props: [ 'alertVisible', ], watch: { alertVisible () { if (this.alertVisible && !this.visible) this.show() else if (!this.alertVisible && this.visible) this.hide() }, ... }, ... 
+4
source

If prop is only useful for this child component, give the child a prop both initialVisible and a data both mutableVisible and hook created (which is called when the component's data structure is assembled), just this.mutableVisible = this.initialVisible .

If support is used by other children of the parent component, you must make it the parent of data to make it accessible to all children. Then in the child of this.$emit('visibleChanged', currentVisible) to notify the parent to change visible . In the parent template, use <ThatChild ... :visibleChanged="setVisible" ...> . Take a look at the manual: http://vuejs.org/v2/guide/components.html

+3
source

Perhaps this looks like a hack and violates the concept of a single data source, but its work) This solution creates a local proxy variable and inherits data from the details. Next work with a proxy variable.

 Vue.component("vote", { data: function() { return { like_: this.like, dislike_: this.dislike, } }, props: { like: { type: [String, Number], default: 0 }, dislike: { type: [String, Number], default: 0 }, item: { type: Object } }, template: '<div class="tm-voteing"><span class="tm-vote tm-vote-like" @click="onVote(item, \'like\')"><span class="fa tm-icon"></span><span class="tm-vote-count">{{like_}}</span></span><span class="tm-vote tm-vote-dislike" @click="onVote(item, \'dislike\')"><span class="fa tm-icon"></span><span class="tm-vote-count">{{dislike_}}</span></span></div>', methods: { onVote: function(data, action) { var $this = this; // instead of jquery ajax can be axios or vue-resource $.ajax({ method: "POST", url: "/api/vote/vote", data: {id: data.id, action: action}, success: function(response) { if(response.status === "insert") { $this[action + "_"] = Number($this[action + "_"]) + 1; } else { $this[action + "_"] = Number($this[action + "_"]) - 1; } }, error: function(response) { console.error(response); } }); } } }); 

use the component and skip the details

 <vote :like="item.vote_like" :dislike="item.vote_dislike" :item="item"></vote> 
0
source

According to the component of Vue.js doc :

When the parent property is updated, it will drain to the child, but not vice versa. So how do we get in touch with a parent when something happens? This is where the Vues custom event system comes in.

Use $emit('my-event) from the child to send the event to the parent. Get the event in the child declaration inside the parent using 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> 
0
source

Source: https://habr.com/ru/post/1012620/


All Articles