Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

vuejs computed setter of given prop is not reactive

Tags:

vue.js

I'm using computed to copy my prop value and use/mutate it in my component:

export default {
  props: ['propOffer'],
  computed: {
    offer: {
      get: function () {
        return JSON.parse(JSON.stringify(this.propOffer))          
      },
      set: function () {
        this.offer
      }
    },
   }

The problem is within using setter. It is not reactive. When I use some kind of input, there is a delay, so my computed offer isn't updating instantly. Example of input:

    <v-text-field
    label="Offer title"
    v-model="offer.title"
    ></v-text-field>

This is far opposite to the behaviour when I declare offer as a variable (wthout computed) - then I got my {{offer}} changes instantly inside the <template>

How can I improve it? Am I setting my computed wrong?

like image 554
gileneusz Avatar asked Dec 08 '25 20:12

gileneusz


1 Answers

To better understand this situation, this is what happens at the moment:

When the application loads, the initial state is:

<your-component>
propOffer: '{"title":"test"}'
offer.<lastValue>: undefined

At the point in time, your application will load the v-text-field, this references field offer, and this inits the offer computed variable:

<your-component>
propOffer: '{"title":"test"}'
offer.<lastValue>: [Javascript object 1]

[Javascript object 1]
title: "test"

<v-text-field>
value: "test"

As the user types into the v-text-field, its value changes, because the v-model emits back updates:

<your-component>
propOffer: '{"title":"test"}'
offer.<lastValue>: [Javascript object 1]

[Javascript object 1]
title: "test123"

<v-text-field>
value: "test123"

As you can see here, the setter is never invoked in the normal operation, and hence your code to save it does not run.

You can solve this by making another computed prop for the title of the offer, and then adding some code to prevent your changes from being made undone.

Let's start with the getter & setter for the title:

computed: {
    title: {
        get() {
            return this.offer.title;
        },
        set(title) {
            this.offer = {...this.offer, title};
        }
    },
    // ....

Now we need to properly handle this set operation inside our main offer function, because if we don't handle it, and basically modify its returned object, we get into the territory of undefined behaviour, as the value of the computation doesn't match the computation.

    // ... 

    offer: {
        get: function () {
            if (this.modifiedOffer) {
                return this.modifiedOffer;
            }
            return JSON.parse(JSON.stringify(this.propOffer))          
        },
        set: function (offer) {
            this.modifiedOffer = offer;
        }
    },
},
data() {
    return: {
        modifiedOffer: undefined,
    };
},

After doing this pattern, you now have a stable application, that shows no undefined behaviour, for more functionality, you basicly need to check if the propOffer changes, and either forcefully delete the this.modifiedOffer, or add more logic to a different computed variable that informs the user there is a data conflict, and ask him to overwrite his data.

like image 57
Ferrybig Avatar answered Dec 10 '25 20:12

Ferrybig