Sorting Lists with Vue.js Composition API Computed Properties

Vue.js empowers developers to create dynamic and interactive user interfaces. One of its core features, computed properties, plays a vital role in achieving this. Computed properties act as convenient helpers, automatically calculating values based on other reactive data within your components. This keeps your templates clean and your logic organized, making development a breeze.

Now, imagine building a cool quotes app in Vue js 3 with script setup and composition API. To make it even cooler, you want to let users sort the quotes by different criteria. Here's where computed properties come in to play! In this quick tutorial, learn how to leverage computed properties to effortlessly sort lists in Vue.js 3.

Step 1: Fetching Quotes

First things first, we need some quotes! We'll leverage an awesome free API called Quotable to fetch a random set of quotes.

Let’s first have a look at the below code snippet for our Single-File Component (SFC) to be more familiar with the starting point of the tutorial.

<script setup>
    import { ref, onMounted } from 'vue';

    const quotes = ref([]);

    const fetchQuotes = async () => {
      const response = await fetch('https://api.quotable.io/quotes/random?limit=5');
      const data = await response.json();
      quotes.value = data.map((quote) => ({ ...quote, rating: Math.floor(Math.random() * 20) + 1 }));
    };

    onMounted(() => {
      fetchQuotes();
    });
</script>

Here’s a quick explanation:

  • We define a variable ref named quotes to store the fetched quotes.
  • The fetchQuotes function asynchronously fetches data from the Quotable API and parses it into JSON format.
  • We map over the fetched quotes, assigning a random rating between 1 and 20 to each one using Math.floor(Math.random() * 20) + 1.
  • Finally, onMounted ensures fetchQuotes runs automatically when the component mounts.

In the above code snippet, I used Vue.js onMounted hook to trigger the function automatically as soon as the component mounts.

Step 2: Using Computed Properties to Sort The Data

Now comes the exciting part, which is sorting the quotes based on their ratings! To do that, we first need to set the criteria. And for that, we define a variable ref named sortOrder to keep track of the sorting direction (ascending or descending).

const sortOrder = ref('desc');

Then, we need a way to keep an eye on the value of this reactive data. Here's where computed properties shine. We can use Vue.js computed properties to constantly calculate different result whenever the sortOrder variable ref is changed.

We can do that by importing computed API from vue , and define it like this:

const sortedQuotes = computed(() => {
    return console.log('I have my eyes on you, sortOrder! ', sortOrder.value)
});

This computed property now will return the value of sortOrder every time the value changes. This way, we can say “return this value, if the sortOrder.value is desc, and this value if it’s asc”

const sortOrder = ref('desc');

const sortedQuotes = computed(() => {
  if (sortOrder.value === 'desc') {
    return console.log('Sorted in desc');
  } else {
    return console.log('Sorted in asc');
  }
});

Let's move past the demonstration examples and dive into implementing the actual sorting logic. The first thing you need to know about computed properties, is that we shouldn’t use it to trigger side-effects. This means that whatever we want to do with it, it should only be used as a getter.

const sortOrder = ref('desc');

const sortedQuotes = computed(() => {
  const quotesCopy = [...quotes.value];
  if (sortOrder.value === 'desc') {
    return quotesCopy.sort((a, b) => b.rating - a.rating);
  } else {
    return quotesCopy.sort((a, b) => a.rating - b.rating);
  }
});

The sortedQuotes computed property utilizes the power of Vue's reactivity. It creates a copy of the original quotes array quotesCopy to avoid modifying the original data.

Based on the sortOrder.value, the quotes are sorted using JavaScript’s sort function:

  • The sort function takes a callback function that compares two elements (quotes in our case). We want to sort by rating, so we compare b.rating with a.rating.
  • If sortOrder.value is 'desc' (descending), quotes with higher ratings will come first (achieved by subtracting a.rating from b.rating).
  • If sortOrder.value is 'asc' (ascending), quotes with lower ratings will be displayed first (achieved by subtracting b.rating from a.rating).

Now, all we need is a function that toggles the sortOrder value.

const sortQuotes = () => {
  if (sortOrder.value === 'desc') {
    sortOrder.value = 'asc';
  } else {
    sortOrder.value = 'desc';
  }
};

Step 3: Putting it All Together

With our sorted quotes in hand, let's create a user-friendly interface for interacting with them:

<template>
  <div>
    <h1>Random Wise Quotes</h1>

    <button @click="sortQuotes">
      Sort By Rating ({{ sortOrder.toUpperCase() }})
    </button>

    <ul>
      <li v-for="quote in sortedQuotes" :key="quote._id">
        <span>Rating: {{ quote.rating }}</span>
        <blockquote>
          <p>{{ quote.content }}</p>
          <cite>- {{ quote.author }}</cite>
        </blockquote>
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref, onMounted, computed } from 'vue';

const quotes = ref([]);

const fetchQuotes = async () => {
  const response = await fetch('https://api.quotable.io/quotes/random?limit=5');
  const data = await response.json();
  quotes.value = data.map((quote) => ({
    ...quote,
    rating: Math.floor(Math.random() * 20) + 1,
  }));
};

onMounted(() => {
  fetchQuotes();
});

const sortOrder = ref('desc');

const sortQuotes = () => {
  if (sortOrder.value === 'desc') {
    sortOrder.value = 'asc';
  } else {
    sortOrder.value = 'desc';
  }
};

const sortedQuotes = computed(() => {
  const quotesCopy = [...quotes.value];

  if (sortOrder.value === 'desc') {
    return quotesCopy.sort((a, b) => b.rating - a.rating);
  } else {
    return quotesCopy.sort((a, b) => a.rating - b.rating);
  }
});
</script>

Inside the template, we render our list by looping through the sortedQuotes computed property to display the quotes in the desired order.

Conclusion

By leveraging Vue.js 3's computed properties, we’ve successfully implemented dynamic quote sorting functionality in the application. This empowers users to explore the quotes by rating, enhancing their overall experience. Remember, computed properties are a versatile tool for various scenarios beyond sorting. They can be used to filter data, format strings, and perform many other calculations based on your reactive data.

For a deeper dive into Vue.js 3's Composition API and computed properties, check out the fantastic free course "Vue.js Fundamentals with the Composition API". This course will equip you with the knowledge to master these concepts and become a Vue.js pro!

Feel free to have a look at the complete implementation code here.

Article originally posted on Vue School