Reputation: 115
What it the best practice for passing a property object in VueJS to a component and modify it there?
For example a table of people (name, first name, age, sex, etc) and with clicking on an entry, a dialog pops up where you can modify the entry.
If I pass the entry to the component via props and modify it, I get "Error message: 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."
Using computed values (which are a possible solution proposed from a lot of tutorials etc.) does not work either because in the getter function I return the property value and in the setter function I set the the new value to the passed property and then the "Avoid mutating..." obviously comes up again.
What I came up with is to store the entry in a Vuex.Store state and use this with a computed property. But it creates a lot of code for each table. Does not look clean for me.
Is there another solutions for this? Seems like a basic problem for me.
Upvotes: 3
Views: 3799
Reputation: 37923
Just pass the object as a whole (single prop of type Object
) and now you can modify the properties of the object in the child component as you wish.
And yes, this is considered anti-pattern by many. Their argument being that the code is hard to reason about if the mutations are all over the code base. Frankly I do not buy the argument. If I create the component and give it the name "PersonEditor" (for example) it is pretty clear what that component does and why and reasonable to expect that it modifies the data passed in...
Using Vuex (or Pinia ...try it, it's great!) has it's value too (central store, time-travel debugging etc.) but in simple cases it is IMHO not reasonable to write (and maintain) tons of boilerplate code just to stick with some dogma...
Also in most real life scenarios when you need to edit some "record", you want also other features. For example "Cancel" button (all changes made by the user must be reverted) or do not propagate intermediate values (that are probably invalid due to a process of user interacting with the form) to the parent or the store. Perfect solution is to make a copy of the object/record (for example using spread operator - if object does not contain deeply nested values), pass it down to a component and get it back using the event when user clicks "Save". Now the code of the "editor" component is much simpler and yet the parent component is responsible for "committing" the changes (replacing original object with the new one)
Just to be clear. There are two different (but similar) error messages. One is coming from the Vue itself at runtime - if you do something like this.propA = 3
in the child. And that's fine as it is really a problem...
The other can come from the ESLint, particularly its Vue plugin/rules. The rule vue/no-mutating-props. And this one will bite you even if you do something like this.propA.someProperty = 3
which is technically correct but it is against "the rules"
Upvotes: 4
Reputation: 1772
I think, in this case, the best practice is for the parent component to pass data as props to its child components. The child component then $emit
s the new value for that prop - Here's a working DEMO
App.vue:
<template>
<div>
<h1>{{ title }}</h1>
<Child @changeTitle="ChangeT($event)" />
</div>
</template>
<script>
import Child from "./components/Child";
export default {
name: "App",
components: {
Child,
},
data() {
return {
title: "Rick Grimes",
};
},
methods: {
ChangeT(title) {
this.title = title;
},
},
};
</script>
<style></style>
Child.vue:
<template lang="html">
<button type="button" @click='passEvent'> Update me</button>
</template>
<script>
export default {
name: "Child",
methods: {
passEvent() {
this.$emit("changeTitle", "Awesome ");
},
},
};
</script>
<style lang="css" scoped>
</style>
Upvotes: 1
Reputation: 81
Try using callback and modify an object in the parent component if you want to avoid store in this scenario. Also, there must be an alternative to componentWillReceiveProps(from React) in VueJs use that as well to keep checking for props change.
Upvotes: 0
Reputation: 331
Mutatiting props is an anit-pattern in Vue, if you want to change prop value then emit new value to parent and modify it there
Upvotes: 0