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:添加 updated
与 console.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 时发生突变,导致其余表发生变化。每日提示:检查是否所有嵌套组件都不依赖于受更改影响的某些存储变量
我在 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:添加 updated
与 console.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 时发生突变,导致其余表发生变化。每日提示:检查是否所有嵌套组件都不依赖于受更改影响的某些存储变量