Vue 不会使用动态组件从 Vuex 更新 v-for 中的项目
Posted
技术标签:
【中文标题】Vue 不会使用动态组件从 Vuex 更新 v-for 中的项目【英文标题】:Vue does not update items in v-for from Vuex with dynamic component 【发布时间】:2019-12-23 00:24:15 【问题描述】:我们有一个tab
body 的动态组件,定义为
<component :is="currentTab.itemType" :itemId="currentTab.itemId"></component>
模板有一个跨度,它反映了itemId
- 每次标签主机组件中的currentTab
更改时,它都会更改。
tab.itemType
的每个组件都有 Vuex 模块,属于它特定的类型。
例如,有描述状态的存储模块product
:
products: [itemId: string]: IProduct
当组件创建或itemId
改变时,它会尝试运行加载动作并将加载的产品置于vuex状态的products
。
所以,有 Vue 计算属性,看起来像
@State(productNamespace)
state: IProductState;
get currentProduct()
return this.state.products[this.itemId];
甚至
@Getter(GetterNames.GET_PRODUCT_BY_ID, bindingOptions)
getProductById: (itemId: string) => IProduct;
get currentProduct()
return this.getProductById(this.itemId);
每个产品都有attributes
列表,由v-for
和:key
迭代。
<v-list :key="itemId"><!-- itemId has no effect there -->
<v-list-item v-for="attribute in currentProduct.attributes" :key="attribute.id">
...
</v-list-item>
</v-list>
问题是:
当我们更改itemId
时,属性列表会显示上次添加产品的所有属性,并且在使用另一个itemId
但相同的itemType
切换到以前的“选项卡”时不会刷新它。
我尝试将父级div
的:key
设置为itemId
,但没有任何效果。
当我将:key
设置为<component>
时,vuex 状态会被破坏。
Vue 版本是 2.6.10
更新:
它也不适用于产品的简单属性:
currentProduct.name
总结:
有itemId
属性。计算属性取决于它。因此,当 itemId
属性更改而 Vuex 集合未更改时,计算属性不会反映更改。
确认:
计算属性仅在 state.products 集合更改时更新。我通过为每个选项卡切换运行 createProduct
操作来模拟这一点。 vuex 状态下的集合接受未观察的产品存根并反映对合法currentProduct
的更改,并带有给定的itemId
更新 2:带有观察者的组件。还是没办法……
@Component
export default class Product extends Vue
@Prop( type: Object, required: true )
readonly tabItem: ITabItem;
@State(productNamespace)
state: IProductState;
itemId: string;
created()
//...
this.initCurrentProduct();
// No changes until state.products was changed.
get currentProduct(): IProduct |
if (!this.state) return ;
return this.state.products[this.itemId];
@Watch('tabItem')
onTabItemChanged()
DEBUG && console.log('Tab changed: keep moving!');
this.initCurrentProduct();
private async initCurrentProduct()
const isNew, itemId = this.tabItem;
if (itemId === this.itemId)
return;
DEBUG && console.log('ItemId changed.');
this.itemId = itemId;
// ...
// ...
【问题讨论】:
您不应该访问 this.$store.state... 而不是 this.$state...? 对不起,我的错 - 我使用'vuex-class',所以有不正确的简化。等一下,我纠正一下。 我记得 Vuex 推荐 getter 用于计算属性,而不是直接访问 Store。您是否尝试过使用吸气剂? 是的,原来是从功能性吸气剂中获取的。似乎只有添加的最后一项反映了它的属性,但切换回来对更改itemId
的计算属性没有影响。所以我认为有products
集合更改事件引发。
我不确定我们是否在同一页面上。你说有一个吸气剂,但在显示的代码中你只是直接访问商店而没有任何吸气剂。计算的属性也是get currentProduct()
- 为什么是空格?它在计算部分吗?
【参考方案1】:
在你的 vuex 突变中
let items = [...state.items]; // create a new copy
// mutate it
items.map(item => item.selected = true);
// return the new copy
state.items = items;
【讨论】:
【参考方案2】:好的,所以您传递给动态组件的属性是 currentTab.itemId
,这意味着 itemId 实际上是 currentTab
对象中的一个元素,而不是根 Vue 数据对象?
Vue 默认不跟踪嵌套对象,它只会在整个对象发生更改时触发重绘(例如,如果您执行currentTab = ...
之类的操作)。您可以:
在currentTab
上使用带有deep: true
属性的观察程序:https://vuejs.org/v2/api/#watch,然后在调用时使用this.$forceUpdate
触发重绘。
将 itemId
移动到数据的根目录,然后从那里更新它
【讨论】:
用观察者和 itemId 作为数据的组件示例更新了问题。仍然没有效果......但是等等!itemId
的初始值是未定义的,所以它不能是响应式的!更改为默认itemId: string = '';
,现在可以使用了!以上是关于Vue 不会使用动态组件从 Vuex 更新 v-for 中的项目的主要内容,如果未能解决你的问题,请参考以下文章