[Vuejs]-VueJS component rerenders when props is unchanged

0👍

Update: I have another component inside Table.vue which was dependent on a store variable which was mutated when changing t1 causing the rest of the tables to change. Tip of the day: check if all the nested component isnt dependent on some store variable effected by the change

0👍

You should probably add some code because what you say you see seems strange…

Look at the following example (updated example to use Vuex…just to be sure)

  • first button mutate the 1st table’s data at index 0. Result = only 1st component re-renders
  • second button completely replaces data for 2nd table. Result = only 2nd component re-renders
  • 3rd button replaces whole tables array by a new array. Result = both component’s re-render (as expected)
  • 4th button for curious people 😉 …completely new tables array composed from existing instances. Result = no re-render at all
  • 5th button (added after Q update)
    • same way of updating as in question
    • Result – only 2nd table rerenders! Clear contradiction to what you say…
    • note that if you have currentViews property in the state from the beggining, you don’t need to use Vue.set – simple assignment will suffice

Update: Added updated hook with console.log into mytable component to check if logs correlate with time changes in tables headers – confirmed

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    tables: [
        ['item 1', 'item 2'],
        ['item 1', 'item 2']
      ]
  },
  mutations: {
    mutate1st(state) {
      Vue.set(state.tables[0], 0, state.tables[0][0]+'+1')
    },
    mutateTables(state) {
      Vue.set(state.tables, 1, ['item 3', 'item 4'])
    },
    replaceTables(state) {
      state.tables = [
        ['item 1', 'item 2'],
        ['item 1', 'item 2']
      ]
    },
    newArrayCreatedFromPreviousOnes(state) {
      state.tables = [...state.tables]  // we are creating new array composed from existing instances
    },
    sameWayAsInQuestion(state) {
      let newList = [...state.tables];
      newList[1] = ['item 5', 'item 6'];
      Vue.set(state, 'tables', newList);
    } 
  }
})

const mytable = Vue.component('mytable', {
  props: ['title', 'data'],
  template: `
    <div>
      <div> {{ title }} ({{ now() }}) </div>
      <div v-for="(item, index) in data" :key="index">{{ item }}</div>
      <hr>
    </div>
  `,
  methods: {
    now() {
      const date = new Date();
      return date.toLocaleTimeString();
    }
  },
  updated() {
    console.log(`${this.title} updated at ${this.now()}`)
  }
})

const app = new Vue({
  store,
  components: { mytable },
  template: `
    <div>
      <button @click="mutate1st">Mutate 1st table data</button>
      <button @click="mutateTables">Mutate tables array</button>
      <button @click="replaceTables">Replace tables array</button>
      <button @click="newArrayCreatedFromPreviousOnes">Just for curiosity...</button>
      <button @click="sameWayAsInQuestion">Same way as in question</button>
      <hr>
      <mytable v-for="(table, index) in $store.state.tables" :key="index" :title="'Table ' + index" :data="table" />
    </div>
  `,
  methods: {
    ...Vuex.mapMutations(['mutate1st', 'mutateTables', 'replaceTables', 'newArrayCreatedFromPreviousOnes', 'sameWayAsInQuestion'])  
  }
})

app.$mount("#app")
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.12/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.5.1/vuex.min.js"></script>
<div id="app"></div>

Leave a comment