PChana
PChana

Reputation: 41

Unexpected side effect in "sortItem" computed property

When I use sortItem, I get the following error: "Unexpected side effect in "sortItem" computed property". How do I solve this problem?

computed:{
    sortItem(){
      return this.items.sort((a,b)=>{
        return b.time - a.time
      })
    }
  },

Upvotes: 2

Views: 2993

Answers (1)

Sumurai8
Sumurai8

Reputation: 20745

You get this error, because Array.prototype.sort sorts an array in place.

What does that mean?

An in-place algorithm modifies the existing data structure instead of creating a copy and modifying that one instead. This means that instead of having one original data structure and one modified data structure, you only have the modified data structure. Doing this is obviously much more space efficient than making a copy.

We can demonstrate this easily with the following snippet. Notice that myUnsortedArray suddenly contains a sorted array, even though we did not do any assignment after the initial one.

let myUnsortedArray = [5, 4, 1, 3, 2];
console.log("Unsorted array", myUnsortedArray); // 5, 4, 1, 3, 2

let mySortedArray = myUnsortedArray.sort();
console.log("Sorted array", mySortedArray); // 1, 2, 3, 4, 5
console.log("Unsorted array again", myUnsortedArray); // 1, 2, 3, 4, 5

Why does it give an error

Computed properties in Vue are meant to be pure functions.

You define how a computed property should be calculated. Behind the scenes Vue will determine which variables your computed property depends on, and will silently recalculate your computed property whenever one of the dependencies changes and the computed property is being used somewhere.

When you introduce side-effects to your computed property, like changing the local state of your component, you introduce hard to debug behaviour. It places assumptions on when, and how, Vue will recompute the computed property. Instead, you should put side-effects in methods, or if you have no other options, in a watcher.

How to fix it

One way of "fixing" it is to copy the array before sorting it. Two ways of doing this are:

[...this.items].sort((a, b) => b.time - a.time)
this.items.slice(0).sort((a, b) => b.time - a.time)

A better way of fixing is, is by sorting the item list whenever you make it, or add to it.

Further reading

To better understand this, I would recommend reading up on "primitives", "references" and "scopes".

Upvotes: 7

Related Questions