1
votes

What is the best practice for the following scenario in terms of clean logic and maintenance?

My use case is that there is a query object whose parameters are a bunch of text and the results of the former query.

I initially thought to structure the code as follow (see pseudocode):

data() {
  return {
     queries : {
       q1 : { data: `${this.text} + ${this.formerResults}` }
       // q2, q3...
     },
     formerResults : ''
  }
},
methods : {
  makeQuery : function() {
    let vm = this;

    axios({ /* param of the query, data : this.queries.q1 */ })
     .then((response) => { vm.formerResults += /* add the results */ })
}

The problem with this is that formerResults does get appended, but results as undefined when injected in the next query q1. I can't tell why, but solved the issue by structuring the query q1 as a computed property.

Can you tell why logic fails when using a property, and works with a computed property?

computed: {
   q1() {
      return {
          // same as above
      }
   }
   // q2, q3 ...
}

and call it in my methods:

axios({ /* param of the query, data : this.q1 */ });

I can see that both parameters text and formerResults are passed.

However, I'd like to group queries (q1, q2, q3..) under a same object queries, like in data(): it is for code clarity, for all those queries will be against the same url, and I might have others.

But trying :

computed: {
    computedQueries : {
       q1() {
          return {
          // same as above
        }
       },
       // q2, q3 ...
    }
}

and call it like that in my methods:

axios({ /* param of the query, data : this.computedQueries.q1 */ })

will result in vue error:

Error in v-on handler: "TypeError: Cannot read property 'q1' of undefined"

Can you clarify how can I group (or nest) computed properties in one object ?

Do I really need to use a computed property in my example, to avoid formerResults be undefined in a next query? Can you suggest how to keep code clean ?

1

1 Answers

2
votes

There are couple of things to consider.

First question: Can you tell why logic fails when using a property, and works with a computed property?

The properties returned from the data() lifecycle method are reactive in a sense that each time you change them, fresh render cycle is triggered by Vue. But that doesn't mean that each reactive property will be automatically updated. You still have to update it. So, when you are doing this:

data() {
  return {
    queries : {
      q1 : {
        data: `${this.text} + ${this.formerResults}` 
      }
    },

    formerResults : ''
  }
},

Vue.js is yet to add these reactive properties to the this instance. Naturally, this.formerResults will be undefined at this point and this.queries.q1 will get it as undefined.

Why and when to use computed properties?

You are right about using computed properties. If you need to establish the dependency relationship automatically and if you don't need a setter (i.e. to set the values yourself) for some property, then you must use computed property.

In your case, the queries - q1, q2, and so on must be automatically updated whenever formerResults changes. For this purpose, you will use computed properties.

How can I group (or nest) computed properties in one object?

Your way to declare computed properties is wrong and thus you see the error. There is no concept of nested computed properties per se, but you can create a single complex object which is a result of multiple calculations and producing the single value holding all the data that you need:

computed: {
  queries: function () {
    return {
      q1: { data: `${this.text} + ${this.formerResults}`},
      q2: { /* Some other stuff */},
      //... q3, q4, etc.
    };
  }
}

Every time text and formerResults is changed by some part of the code, your queries object will be re-calculated. There won't be any performance penalty as such.

Do I really need to use a computed property in my example, to avoid formerResults be undefined in a next query? Can you suggest how to keep code clean?

Using computed property is the cleanest way to achieve reactivity. In my opinion, every other alternative is cumbersome. For example, you can do the same using watchers but it is not clean.

data() {
  return {
    queries: {
      q1: { data: '' },
      // q2, q3, ...
    },
    formerResults: ''
  }
},
watch: {
  formerResults: function() {
    this.queries = {
      q1: { data: `${this.text} + ${this.formerResults}` }
      // q2, q3, ...
    };
  },
  text: function() {
    this.queries = {
      q1: { data: `${this.text} + ${this.formerResults}` }
      // q2, q3, ...
    };
  }
}