Home > OS >  Vue 3 remove component prop reactivity
Vue 3 remove component prop reactivity

Time:03-14

I have and EditTransaction component and calling it just like this:

<edit-transaction
    v-if="editableTransaction.id === transaction.id"
    :key="'transaction' transaction.id etcount"
    :
    :groups-prop="modelValue"
    :transaction="transaction"
    
    @close="editableTransaction = {id: null}">
</edit-transaction>

As you can see, I'm sending a transaction object in it. Since this is an editor, I don't want the transaction object to be reactive. If somebody closes the editor, I want to have the original transaction object and not some modified one, so if I'm correct and want to remove the proxy I put this in the editor:

const form = toRaw(props.transaction)

And inside the editor template, there are some asset components which v-model values bind to the form object

<div >
    <FormInput id="et-date" v-model="form.due_date" 
               placeholder="Date"
               type="date"
               @keyup.enter="saveChanges"></FormInput>
    <FormInput id="et-name" v-model="form.name"  placeholder="Name"
               @keyup.enter="saveChanges"></FormInput>
    <FormInput id="et-value" v-model="form.value"  mask-thousand
               placeholder="Value"
               @keyup.enter="saveChanges"></FormInput>
</div>

The problem is when I'm changing like the transaction name for example, the form object changes but also the transaction prop. Therefore the name changes also in the parent data because the transaction prop is reactive. What am I doing wrong or how can I achieve to have a form object which values got filled up upon component create with the props value and does not have any proxies?

enter image description here

CodePudding user response:

It's very common to use props to pass initial values to child component's state. This means that you "copy" the value of a prop in the local data. It keeps the prop value safe of unexpected changes: Read more in Vue docs

This is a pretty simple example showing the above approach:

/your-child-component-vue/

export default {
  props: ['initialCounter'],
  data() {
    return {
      // counter only uses this.initialCounter as the initial value;
      // it is disconnected from future prop updates.
      counter: this.initialCounter
    }
  }
}

Now, reading your example, I see that you're trying to update some data in a form, and you don't want to change the initial information unless it's confirmed by a button or something. The flow to approach this would be:

  • Pass the initial data that may be changed by the user as a prop.
  • If the user changed some data through inputs elements but not confirmed those changes (by a button) keep the data untouched (this means that you would not emit any changes to the parent, keeping the prop value untouched)
  • If user has changed some data and also confirmed it, emit this updated data to the parent (this.$emit) so It knows about the changes.

CodePudding user response:

So I found two solutions for this:

const form = reactive({...props.transaction})

or

const form = Object.assign({}, props.transaction)

Both works and when I change the form value, it won't mutate the prop.

  • Related