Introduction

In Vue 2, the reactivity system cannot detect direct array index assignment or length modification due to JavaScript limitations. When you set an array item by index, the view does not update:

javascript
// Vue 2 - this will NOT trigger a re-render
this.items[3] = 'new value';
this.items.length = 2;

Vue 2 uses Object.defineProperty for reactivity, which cannot intercept array index access. Vue 3 solves this with Proxy-based reactivity.

Symptoms

  • Array items change in data but the template does not update
  • v-for loop does not reflect changes to array elements
  • Computed properties depending on the array return stale values
  • Vue DevTools shows the updated array but the UI does not reflect it
  • Works for push() and pop() but not for direct index assignment

Common Causes

  • Direct index assignment: this.items[index] = value
  • Direct length modification: this.items.length = newLength
  • Adding new properties to objects inside arrays
  • Using array methods that Vue 2 does not override (custom mutations)
  • Nested array modifications deep within object structures

Step-by-Step Fix

  1. 1.Use Vue.set (or this.$set) for reactive index assignment in Vue 2:
  2. 2.```javascript
  3. 3.// BAD
  4. 4.this.items[3] = 'new value';

// GOOD this.$set(this.items, 3, 'new value'); // Or Vue.set(this.items, 3, 'new value'); ```

  1. 1.Use splice as an alternative to direct index assignment:
  2. 2.```javascript
  3. 3.// BAD
  4. 4.this.items[3] = 'new value';

// GOOD this.items.splice(3, 1, 'new value');

// For setting length this.items.splice(2); // Equivalent to this.items.length = 2 ```

  1. 1.Replace the entire array to trigger reactivity:
  2. 2.```javascript
  3. 3.// Create a new array reference
  4. 4.this.items = this.items.map((item, index) =>
  5. 5.index === 3 ? 'new value' : item
  6. 6.);
  7. 7.`
  8. 8.For nested object properties in arrays, use Vue.set:
  9. 9.```javascript
  10. 10.// BAD
  11. 11.this.users[0].profile.name = 'John';

// GOOD this.$set(this.users[0].profile, 'name', 'John'); // Or replace the entire object this.users[0] = { ...this.users[0], profile: { ...this.users[0].profile, name: 'John' } }; ```

  1. 1.Upgrade to Vue 3 which uses Proxy-based reactivity that detects all mutations:
  2. 2.```javascript
  3. 3.// Vue 3 - all of these work reactively
  4. 4.items[3] = 'new value'; // Works
  5. 5.items.length = 2; // Works
  6. 6.items.push('new item'); // Works
  7. 7.items.splice(1, 1); // Works
  8. 8.`

Prevention

  • Avoid direct array index assignment in Vue 2 - always use $set or splice
  • Use immutable patterns (map, filter, spread) to create new array references
  • In Vue 3, direct mutations work, but prefer immutable patterns for predictability
  • Add ESLint rules to warn about direct index assignment in Vue 2 projects
  • Test array mutations in component unit tests to verify reactivity
  • Document Vue 2 reactivity caveats in your team's development guide
  • Consider migrating to Vue 3 where Proxy-based reactivity eliminates these issues entirely