javascriptvue.jsvuejs2better-sqlite3

Updating item in array of objects in Vue.js: is it better to replace the array or change one value


I'm using Vue/Vuex to generate components from an array with this structure (retrieved from SQLite using better-sqlite3).

let table=[
  {
    id:1,
    column_1:'data',
    column_2:'data',
    column_3:{'1':'data','2':'data','3':'data'}
  },
  {
    id:2,
    column_1:'data',
    column_2:'data',
    column_3:{'1':'data','2':'data','3':'data'}
  },
  ...
]

There are cases where the data of multiple rows need to be updated at once. Since I need to pass data back and forth between SQLite and Vue, I'm wondering whether it'll be simpler and harmless to update the data with sql and then replace the entire javascript array with the updated data, including the unmodified rows. Otherwise I imagine I'll have to use .find() to go through and change the specific items. So my question is whether replacing the whole array is a Bad Idea as far as reactivity goes, or whether Vue can smart update accordingly.


Solution

  • Vue has a different way of tracking when it comes to update the UI

    Vue uses getters/setters on the data object for mutation tracking. When you execute this.table = [{}, {}, {}, ...];, It will go through the setter of table. In the setter, there's a function to notify the watcher and add this data changes to a queue.

    Limitation/Behaviour while updating the Arrays :

    Vue cannot detect the following changes to an array :

    1. When you directly set an item with the index, e.g. vm.items[indexOfItem] = newValue
    2. When you modify the length of the array, e.g. vm.items.length = newLength

    Demo as per above two statements :

    const app = new Vue({
      el: '#app',
      data() {
        return {
          table: [{
            id:1,
            column_1:'data1',
            column_2:'data',
            column_3:{'1':'data','2':'data','3':'data'}
          }, {
            id:2,
            column_1:'data2',
            column_2:'data',
            column_3:{'1':'data','2':'data','3':'data'}
          }]
        }
      },
      mounted() {
        // We are updating the array item and It's not reactive (You can see it's not updating UI)
        this.table[1] = {
          id: 3,
          column_1: 'data3',
          column_2:'data',
          column_3:{'1':'data','2':'data','3':'data'}
        }
      }
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <div id="app">
      <ul>
        <li v-for="item in table" :key="item.id">
          {{ item.column_1 }}
        </li>
      </ul>
    </div>

    Answer of your Question : In consideration of above two statements, You have to update whole array including the unmodified rows.

    Demo as per the answer of your question :

    const app = new Vue({
      el: '#app',
      data() {
        return {
          table: [{
            id:1,
            column_1:'data1',
            column_2:'data',
            column_3:{'1':'data','2':'data','3':'data'}
          }, {
            id:2,
            column_1:'data2',
            column_2:'data',
            column_3:{'1':'data','2':'data','3':'data'}
          }]
        }
      },
      mounted() {
        // We are updating the whole array and It's reactive (You can see it's updating UI)
        this.table = [{
            id:1,
            column_1:'data1',
            column_2:'data',
            column_3:{'1':'data','2':'data','3':'data'}
          }, {
          id: 3,
          column_1: 'data3',
          column_2:'data',
          column_3:{'1':'data','2':'data','3':'data'}
        }]
      }
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <div id="app">
      <ul>
        <li v-for="item in table" :key="item.id">
          {{ item.column_1 }}
        </li>
      </ul>
    </div>