Skip to content

noVueSideEffectsInComputed (JavaScript)

Language JavaScript (and super languages)
biome.json
{
"linter": {
"rules": {
"nursery": {
"noVueSideEffectsInComputed": "error"
}
}
}
}

Disallow changing state inside Vue computed properties.

A computed property should only calculate a value from other values and return it. Vue decides when to run it: it may run it many times, or reuse the last result without running it at all. When a computed property also changes state, such as assigning to a variable or sorting an array, those changes happen at times that are hard to predict, and the component becomes hard to understand.

This rule reports code in the function that calculates a computed property when that code:

  • assigns to, increments, or deletes a property of the component (this.count++), or of a variable declared in setup() or in <script setup> (user.value.name = "");
  • calls an array method that changes the array itself instead of returning a new one: copyWithin(), fill(), pop(), push(), reverse(), shift(), sort(), splice() or unshift();
  • passes such a value as the first argument of Object.assign(), which changes it.

Changes to variables declared inside the computed property are allowed, because no other code can see them. A computed property can also have a set function, which runs when a new value is assigned to the property. That function isn’t checked, because changing state is its purpose.

<script>
export default {
computed: {
reversedItems() {
return this.items.reverse();
},
},
};
</script>
code-block.vue:5:14 lint/nursery/noVueSideEffectsInComputed ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ The computed property reversedItems changes state.

3 │ computed: {
4 │ reversedItems() {
> 5 │ return this.items.reverse();
│ ^^^^^^^^^^^^^^^^^^^^
6 │ },
7 │ },

ℹ Vue decides when to run a computed property, and skips running it again while the values it reads stay the same. Changes made inside it happen at unpredictable times.

ℹ Make the change in a method or a watcher instead. To sort or reverse an array, work on a copy, as in [...items].reverse().

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

<script setup>
import { computed, ref } from "vue";
const count = ref(0);
const doubled = computed(() => {
count.value++;
return count.value * 2;
});
</script>
code-block.vue:6:3 lint/nursery/noVueSideEffectsInComputed ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ The computed property doubled changes state.

4 │ const count = ref(0);
5 │ const doubled = computed(() => {
> 6 │ count.value++;
│ ^^^^^^^^^^^^^
7 │ return count.value * 2;
8 │ });

ℹ Vue decides when to run a computed property, and skips running it again while the values it reads stay the same. Changes made inside it happen at unpredictable times.

ℹ Make the change in a method or a watcher instead. To sort or reverse an array, work on a copy, as in [...items].reverse().

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

<script setup>
import { computed, ref } from "vue";
const items = ref([]);
const reversedItems = computed(() => [...items.value].reverse());
const total = computed(() => {
let sum = 0;
for (const item of items.value) {
sum += item.price;
}
return sum;
});
</script>