Handling Nested Array Updates in Vue’s Reactivity System

In Vue’s reactivity model, direct mutations inside nested arrays may not always trigger view updates automatically. Understanding how to correctly propagate changes ensures the UI stays consistent with the underlying data.

Consider a sceanrio where we have a hierarchical data structure—an array of items, each potentially containing a children array with the same shape. The task is to delete an item by its id, searching recursively through all levels.

A recursive utility function can handle the removal. The key is that when a child array is modified during recursion, the parent item must be replaced within its containing array using Vue’s reactive array method splice to guarantee change detection.

Here is one implementation:

deleteItemById(items, targetId) {
  for (let idx = 0; idx < items.length; idx++) {
    const current = items[idx];
    if (current.id === targetId) {
      items.splice(idx, 1);
      return items;
    }
    if (current.children && current.children.length) {
      const updatedChildren = this.deleteItemById(current.children, targetId);
      const replacement = { ...current, children: updatedChildren };
      items.splice(idx, 1, replacement);
    }
  }
  return items;
}

The method iterates over the items. If a direct match is found, it removes the element using splice and returns immediately. If the current item has children, the function calls itself recursively. The resulting child array is then used to create a shallow copy of the parent via the spread operator, and the original parent is swapped out with items.splice(idx, 1, replacement). This explicit replacement notifies Vue of the internal change.

Example data structure:

data() {
  return {
    items: [
      {
        id: '1',
        code: '0001',
        name: 'Item Alpha',
        status: 'active',
        remark: 'Sample remark'
      },
      {
        id: '2',
        code: '0002',
        name: 'Item Beta',
        status: 'active',
        remark: 'Sample remark',
        children: [
          {
            id: '01',
            code: '00001',
            name: 'Sub Beta-1',
            status: 'active',
            remark: ''
          },
          {
            id: '02',
            code: '00002',
            name: 'Sub Beta-2',
            status: 'inactive',
            remark: '',
            children: [
              { id: '001', code: '000001', name: 'Deep Item 1', status: 'active', remark: '' },
              { id: '002', code: '000002', name: 'Deep Item 2', status: 'active', remark: '' }
            ]
          }
        ]
      },
      { id: '3', code: '0003', name: 'Item Gamma', status: 'active', remark: '' },
      { id: '4', code: '0004', name: 'Item Delta', status: 'inactive', remark: '' }
    ]
  };
}

It’s important to remember that spreading objects (...obj) or arrays ([...arr]) creates only a shallow copy. For deeply nested structures requiring a disconnected clone, JSON.parse(JSON.stringify(source)) delivers a full deep copy.

Tags: Vue.js Reactivity Nested Arrays javascript

Posted on Fri, 08 May 2026 22:39:25 +0000 by hush2