VueJS 组件在 props 不变时重新渲染

VueJS component rerenders when props is unchanged

我在 vuex 存储中有一个包含 tables[t1,t2] 的列表,当 t1 更新时,我必须改变 tables 数组以使 t1 更新。

对于每个 table,我使用 <Table v-for="(item, index) in tables" :key="index" :data="item">,而它使用 Table.vue。在 Table.Vue 我有:

 props: {
   data: {
     type: Object,
     default: null
   }
 },

但是当 t1 发生变化时,它也会强制更新 t2,这是可以理解的,因为存储中的整个“tables”变量都发生了变异。但我只希望组件在 props 发生实际变化时更新,这样 t2 就不会不必要地更新。我试图研究记忆,我之前在 React 项目中使用它来解决这个问题。我没有真正找到任何易于使用的东西,搜索“memoization vuejs”并没有真正给我很多继续下去的机会。

为了改变 table:

我在 vuex 商店的突变中做了什么
 my_mutation(state, data) {
    let newList = [...state.tables];
    let index = newList.findIndex(i => i.tableName === data.tableName);
    if (index !== -1) {
       newList[index] = data.value;
    } 
    Vue.set(state, 'currentViews', newList);
}

如您所见,此代码当时仅改变 state.tables 中的 1 个元素,但会设置整个 tables 变量。这会导致 update() 函数在组件中触发(注意不是 created() 因为这只会在我获取并填充 tables 变量时发生)并重新呈现组件。

由于 created() 在突变发生时没有被触发,这告诉我组件仍然存在,不需要重新创建。这里的目标不是在 props 没有更改时触发 updated() 并防止重新渲染该特定组件。

您可能应该添加一些代码,因为您所说的您所看到的看起来很奇怪...

查看以下示例(更新示例以使用 Vuex...只是为了确定)

  • 第一个按钮在索引 0 处改变第一个 table 的数据。结果 = 只有第一个组件 re-renders
  • 第二个按钮完全替换了第二个 table 的数据。 结果 = 只有第二个组件 re-renders
  • 第 3 个按钮用新数组替换整个 tables 数组。 结果 = 两个组件的 re-render(如预期)
  • 好奇者的第 4 个按钮 ;) ...由现有实例组成的全新 tables 数组。 结果 = 完全没有re-render
  • 第五个按钮(Q更新后添加)
    • 与问题相同的更新方式
    • 结果 - 仅第 2 table 重新呈现!与你所说的明显矛盾...
    • 请注意,如果您从一开始就在 state 中有 currentViews 属性,则不需要使用 Vue.set - 简单的赋值就足够了

Update:添加 updatedconsole.log 挂钩到 mytable 组件中以检查日志是否与 [=69= 中的时间变化相关联]s headers - 确认

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>

更新:我在 Table.vue 中有另一个组件,它依赖于一个存储变量,该变量在更改 t1 时发生突变,导致其余表发生变化。每日提示:检查是否所有嵌套组件都不依赖于受更改影响的某些存储变量