David Atanda Building scalable applications on the web.

Understanding computed properties in Vue.js

6 min read 1791

Vue Computed Properties

In Vue.js, there are several ways to set static or dynamic values to display on the template. These include using text interpolation, directly hardcoding into your HTML, or even using simple expressions to modify the data.

This is where computed properties come in super handy. In this tutorial, we’ll go over the basics of using computed properties in Vue.js. We’ll then put all our newfound skills into practice by building a live example app.

Here’s what we’ll cover:

What are computed properties in Vue.js?

In Vue.js, computed properties enable you to create a property that can be used to modify, manipulate, and display data within your components in a readable and efficient manner.

You can use computed properties to calculate and display values based on a value or set of values in the data model. It can also have some custom logic that is cached based on its dependencies, meaning it doesn’t reload but does have a dependency that changes, allowing it to somewhat listen to changes and act accordingly.

For a basic example, consider the computed property count:

<template>
  <div class="hello">
    <h1>{{ count }}</h1>
  </div>
</template>


<script>
export default {
  name: "HelloWorld", 
  data() {
    return {
      shopNumber: 2
    }
  },
  computed: {
    count: function() {
      return 'The shop number is ' + this.shopNumber 
    }
  }
};
</script>

The count property receives the this.shopNumber as a dependency from the data function, then returns a sentence containing the this.shopNumber and it’s made available directly to the template.

How are computed properties used in Vue.js?

You can use computed properties to solve more complex problems. Let’s detail a few more use cases in which Vue.js computed properties come in handy.

Filtering data

Computed properties are great for filtering data. For instance, let’s say you’re filtering an array from an input search bar.

In the data function below, we have an array, userData, containing information we want to display in the component, but we also need to allow the user to filter what is displayed by searching with an input tag (bound with the data property searchQuery). All this is done within the computed property resultQuery:

We made a custom demo for .
No really. Click here to check it out.

export default {
  name: "HelloWorld",
  data() {
    return {
      userData: [
        {
          image:
            "https://pbs.twimg.com/profile_images/1347769407892811786/fJyOAatX_400x400.jpg",
          name: "Tunde",
          uid: "LfhxERlvyfh2auIY0HnpidjJg3L2",
        },
        {
          name: "bola",
          image:
            "https://pbs.twimg.com/profile_images/1355220122512863234/0NZI8bzI_400x400.jpg",
          uid: "R6lyXuNwZfc9ztLDfIZBSZLg2QD2",
        },
        {
          uid: " k8ZVBdA9wfetiB8vJV3Qc07NZty1",
          image:
            "https://pbs.twimg.com/profile_images/1321720900274868224/w5iM_Ads_400x400.jpg",
          name: "Supreme",
        },
      ],
      searchQuery: null
    };
  },
  computed: {
    resultQuery() {
      if (this.searchQuery) {
        return this.userData.filter((item) => {
          return this.searchQuery
            .toLowerCase()
            .split(" ")
            .every((v) => item.name.toLowerCase().includes(v));
        });
      } else {
        console.log(this.userData);
        return this.userData;
      }
    },
  },
};

In our template, searchQuery is bound to the search input tag and the data returned from th resultQuery is looped to be displayed in the component.

<template>
  <div>
    <input v-model="searchQuery" type="text" placeholder="Search the name">
    <div
      class="Chatroom__list__messages"
      v-for="result in resultQuery"
      :key="result.image"
    >
      <div class="Chatroom__list__messages__img">
        <img :src="result.image" />
      </div>
      <div class="Chatroom__list__messages__message">
        <div class="Chatroom__list__messages__message__name">
          <div class="Chatroom__list__messages__message__name__indi">
            {{result.name}}
          </div>
          <div class="Chatroom__list__messages__message__name__time">
            yesterday
          </div>
        </div>
        <div class="Chatroom__list__messages__message__details">
          message from supreme
        </div>
      </div>
    </div>
  </div>
</template>

Basically, resultQuery checks whether the user has typed anything in the input tag bound to searchQuery. Then, it filters with the userData.name. If the user hasn’t searched anything, it returns the entire userData array.

I’ve created a live example on CodeSandbox.

Calculations

In the same vein, we can use computed properties to handle calculations. All we need to do is pass the dependency into the property, write the calculation we need it to execute, then return the answer:

<script>
export default {
  name: "ComputedCalculation",

data() {
  return {
    number: 2
  }
},
computed: {
  totalMarks() {
    return this.number * 2;
  }
}
};
</script>

We have a computed property totalMarks where we pass in a dependency (number) from the data function and multiply it by two:

<template>
  <div class="hello">
    <h1>{{ totalMarks }}</h1>

  </div>
</template>

Here’s a live example.

In our template, we simply call the computed property name within it and the value displays in the component. This might seem like a relatively simple example, but imagine you’re building a financial calculator and dealing with multiple dependencies and more complex calculations, such as compound interest:

Compound Interest = P [(1 + i)n – 1]

Where:

  • P is principal
  • i is nominal annual interest rate in percentage terms
  • n is number of compounding periods

Writing this formula directly into your template is not good for code readability, and it’s definitely not scalable.

Boolean conditionals within the v-if

You can use computed properties to check whether a condition is true, then use v-if within our template to determine whether to display a block of code or not.

Here, the displayBoolean is set to true by default and is set as a dependency to the computed property display. Within display, we can check whether the display property is true. If it is, then we return true; otherwise, we return false:

<script>
export default {
  name: "HelloWorld",

data() {
  return {
    displayBoolean: true
  }
},
computed: {
  display() {
    if(this.displayBoolean) {
      return true
    }
    else return false
  }
}
};
</script>

The result from display is fed into the v-if in our template to determine whether the block of code will be displayed or hidden. We then create a button to toggle the value of displayBoolean for demonstration purposes:

  <template>
  <div class="hello">
    <h2 v-if="display">Display conditionally</h2>
    <button @click="displayBoolean = !displayBoolean">Toogle</button>
  </div>
</template>

Using computed properties with mapGetters

Considering we’re using mapGetters, we can use computed properties to access the data retrieved from our getters.

In the example below, we rename our getter getChatInfo to chatData and return the data within the getter through our chatInfo computed property:

<script>
import { createNamespacedHelpers } from "vuex";
const { mapGetters } = createNamespacedHelpers("chat");
export default {
  name: "Chat",
  computed: {
    ...mapGetters({
      chatData: "getChatInfo",
    }),
    chatInfo() {
      console.log(this.chatData);
      return this.chatData;
    },
  },
};
</script>
<template>
  <div class="hello">
    <h1>{{ chatInfo.name }}</h1>
    <h1>{{ chatInfo.message }}</h1>
  </div>
</template>

Using computed properties as setters

Although rather unorthodox, you can also use computed properties to set data rather than just retrieve data as a computer getter.

We can define a computed setter like this:

<script>
export default {
  name: "HelloWorld",
  data () {
    return {
      firstName: ""
    }
  }, 
  computed: {
    theFullName: {
      get () {
        return `${this.firstName}`
      },
      set (fullName) {
        this.firstName = fullName
      }
    }
  }
};
</script>

theFullName is a computed property that has the ability to set data by binding the computed property to the content of an input tag using v-model. Here, we manipulate the value of the data property firstName by typing and seeing it change in real time:

<template>
  <div class="hello">
    <h1>{{ theFullName }} </h1>
    <input v-model="theFullName" type="text">
  </div>
</template>

Check out a live example.

Computed properties example: Building a shopping cart in Vue.js

To put we’ve learned into practice, let’s create a shopping cart in Vue.js that allows the user to pick the quantity of an item they want, calculate the cost of multiple items, and calculate the total including shipping fees.

Note: For the sake of demonstrating computed properties, the code for this example app may not look entirely DRY.

Each item has a fixed price of $5.00. The user selects the quantity they need, and this is then bound to the computed property quantity, which acts as both a getter and setter. The total price of each item (quantity * unit price) is calculated in a computed property called priceCalc. This process is replicated for the second item with quantity2 and priceCalc2:

<script>
export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    return {
      qty: 1,
      price: 5,
      qty2: 1,
      price2: 5,
      showTotal: false
    }
  },
  computed: {
    quantity: {
      get() {
        return `${this.qty}`
      },
      set(theQuantity) {
        this.qty = theQuantity
      }
    },
    priceCalc () {
      return this.qty * this.price
    },
    quantity2: {
      get() {
        return `${this.qty2}`
      },
      set(theQuantity) {
        this.qty2 = theQuantity
      }
    },
    priceCalc2 () {
      return this.qty2 * this.price2
    },
    subtotal () {
      return this.priceCalc + this.priceCalc2
    },
    shipping () {
      return (2 * 10)/ this.subtotal || ''
    }
  },
  methods: {
    switchView() {
      this.showTotal = !this.showTotal
    }
  }
};
</script>

The addition of the total cost of individual items is done in the computed property subtotal, and shipping is calculated using the same pattern. total is the sum of all the costs including shipping.

We have a button that hides and shows our subtotal, shipping, and total. This is done by having a data property showTotal set to false and toggling it within the method switchView. Clicking the button triggers the switchView function.

Computed properties vs. methods

Computed properties and methods in Vue.js might seem interchangeable, but technically they affect Vue apps differently.

Computed properties cache results, meaning a computed property only executes once after the component is mounted except for any of its dependency changes. A method, meanwhile, executes every time that method is called in the component.

Computed properties and methods have different use cases. It often depends on whether you want a function to execute every time regardless of dependency.

Imagine, for example, that you have a Math.random() within a function and you want it to reload every time. In this case, you’d need to use a method instead of a computed property.

Caching helps improve performance by reducing the number of reloads and requests the application needs to make.

Conclusion

Computed properties are pretty much a necessity in Vue.js because they allow you to read and write cleaner, scalable, and more readable code.

Now that you understand some basic use cases for computed properties, I’d encourage you to read the official Vue.js documentation and explore further on your own to see what you can do with computed properties in Vue.js.

Experience your Vue apps exactly how a user does

Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, try LogRocket. https://logrocket.com/signup/

LogRocket is like a DVR for web apps, recording literally everything that happens in your Vue apps including network requests, JavaScript errors, performance problems, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.

The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error, and what state the application was in when an issue occurred.

Modernize how you debug your Vue apps - .

David Atanda Building scalable applications on the web.

Leave a Reply