This is an excerpt from my 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:
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:
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.
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:
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:
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.
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.
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 loadsimmediate: true,handler() {// Recalculate and set the `topThree` variablethis.topThree = this.getTopThree(this.list);},},},methods: {getTopThree(list) {// Sort the arraylist.sort();// Return first 3 itemsreturn 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:
list
prop changes, our watcher firesthis.list
to our getTopThree
method to calculate the top 3 itemsWe'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.
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 arraylist.sort();// Return first 3 itemsreturn 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 arraylist.sort();// Return first 3 itemsreturn 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 arraylist.sort();// Return first 3 itemsreturn 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 effectsconst copy = this.list.slice();// Sort the arraycopy.sort();// Return first 3 itemsreturn 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:
I think you'd probably agree with me that the approach with computed props is easier to understand as well.
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.
You can also find out more about the course here.