This is an excerpt from my upcoming course Clean Components. You can learn more about it here.

It is Lesson 1 of Module 3 — Perfecting computed props.

I've said it before and I'll say it again:

Computed properties are the most important feature of Vue.

Sure, scoped slots let you create some nice abstractions and watchers are useful too.

But I don't think anything comes close to how valuable computed props are.

There are two main reasons why I think this:

  1. Computed props allow you to write more declarative code
  2. Declarative code is better code

Since this all has to do with declarative code, let's spend a bit of time understanding what exactly that is.

By the end of this lesson you'll have learned:

  • What declarative code is, and how it's different from imperative code
  • Why you already love declarative code — even if you don't know it yet!
  • How computed props allow us to write more declarative code
  • Exactly why writing code declaratively is so important

In the lessons that follow we'll look at different ways that you can use computed props for a lot more than you are right now.

Many components have way too many props, and computed properties can help us clean that up.

But I'm getting ahead of myself.

What is declarative code?

The most common way of programming a computer is to give it a list of instructions. The computer will then go through each instruction step-by-step until the program finishes.

This is called imperative programming.

It's like you're explaining your favourite pasta recipe to someone who has never cooked in their life.

You can't just tell them the ingredients for the sauce and expect them to produce something delicious. They need to know every single step in the most detail possible:

  • Slice the mushrooms

    • Hold the knife like this
    • Slice them this thick
  • Boil the pasta

    • Put in this much water
    • Add a bit of salt
    • Do this to make sure the pot doesn't boil over

If you leave any detail out, they'll probably make a mistake and ruin the dish 😢

But what if you were explaining this recipe to someone who has experience cooking?

Your instructions would look like this instead:

  • Slice the mushrooms
  • Boil the pasta
  • Heat up some butter and cream in a sauce pan
  • Mix in garlic, parmesan, cream cheese, salt and pepper

You don't need to specify how to do each of those things, because the chef knows that. All you need to do is to tell them what they are making.

This is called declarative programming.

Instead of specifying every single step of the program, you only need to tell the computer what should happen, and it knows how to handle the rest.

This is why you love Vue so much

The reason that you and so many others love Vue is that it follows this exact approach.

If you write a template with a v-for, you don't need to write any logic that loops through an array and adds new elements to the DOM, one for each item in the array.

You don't need to worry about what happens when that array changes. You don't have to worry about how to go through the DOM element by element and update them to make sure they're in sync with the data.

Vue does all of that for us. We just have to tell Vue what we want it to do.

This is an extremely powerful and liberating concept. It makes development so much simpler and easier to do!

We want to take advantage of this as much as we possibly can, and write as much of our code as declarative code, not imperative code.

And computed props are how we'll do just that.

Computed props allow you to write declarative code

We have a component here that takes in a list prop, but always renders just the top 3 items:

export default {
  props: {
    list: {
      type: Array,
    },
  },

  data() {
    return {
      topThree: [],
    };
  },

  watch: {
    list: {
      // Run as soon as the component loads
      immediate: true,
      handler() {
        // Recalculate and set the `topThree` variable
        this.topThree = this.getTopThree(this.list);
      },
    },
  },

  methods: {
    getTopThree(list) {
      // Sort the array
      list.sort();

      // Return first 3 items
      return list.slice(2);
    }
  }
}

Our component state topThree will always contain the top three items in the list, no matter how the list prop changes.

Step-by-step, this is what it's doing: 1. If the list prop changes, our watcher fires 1. We pass this.list to our getTopThree method to calculate the top 3 items 1. We take those items and update our component state

We're following an imperative approach here, by specifying exactly what needs to happen.

Actually, our watcher is somewhat declarative, because we don't need to write any logic to check when props update. Vue just runs the function for us when the list prop changes.

But if we switch to using a computed prop, we end up with a more declarative approach. You'll also see that it's a simpler and more understandable way of writing this functionality.

Declarative code is better code

To switch this to a computed prop we'll first get rid of the watcher completely:

export default {
  props: {
    list: {
      type: Array,
    },
  },

  data() {
    return {
      topThree: [],
    };
  },

  methods: {
    getTopThree(list) {
      // Sort the array
      list.sort();

      // Return first 3 items
      return list.slice(2);
    }
  }
}

We can also get rid of our data section as well:

export default {
  props: {
    list: {
      type: Array,
    },
  },

  methods: {
    getTopThree(list) {
      // Sort the array
      list.sort();

      // Return first 3 items
      return list.slice(2);
    }
  }
}

Now we can convert the method into a computed prop that we'll call topThree:

export default {
  props: {
    list: {
      type: Array,
    },
  },

  computed: {
    topThree(list) {
      // Sort the array
      list.sort();

      // Return first 3 items
      return list.slice(2);
    }
  }
}

However, computed props can't accept any arguments. Instead we'll just grab the list prop directly from inside the computed prop:

export default {
  props: {
    list: {
      type: Array,
    },
  },

  computed: {
    topThree() {
      // Copy the list to avoid side effects
      const copy = this.list.slice();

      // Sort the array
      copy.sort();

      // Return first 3 items
      return copy.slice(2);
    }
  }
}

As we saw in Lesson 2.2 — Mutating an Array, we have to make a copy of this list first so we don't accidentally modify it and produce a confusing side effect.

Here are some of the benefits that we can already see just from looking at this small illustration:

  • Less code — Our component here went from 33 lines to 19, a significant reduction
  • Much simpler — Instead of four different pieces in our component (props, data, watcher, and methods) we just have two to think about (props and computed)
  • Focused on our goals — We're not wasting our time with writing code to trigger the update, which has nothing to do with the feature that we're trying to write. This is especially important when someone is trying to read the code and understand what it's doing.

I think you'd probably agree with me that the approach with computed props is easier to understand as well.

Summary

In this lesson we explored what declarative code is, and saw that one of the reasons why people love Vue so much is because it allows us to write our code more declaratively.

We also saw that computed props are the main way that we can convert our imperative code to be more declarative, and saw that there are several benefits to writing code this way.

Because of this, computed props are the most important feature in Vue in my opinion — hopefully I've convinced you.

If you're not convinced yet, the next two lessons cover how we can make computed props extremely composable, and how we can use computed props for (nearly) everything.

Stay tuned for more excerpts and teasers from the course as we get closer to the launch date!

You can also find out more about the course here.