被销毁的 Vue 组件的 Mixin 仍在监听事件
Mixin for destroyed Vue component is still listening for events
我有一个有条件地呈现两个子组件之一的父组件:
<template>
<div>
<!-- other code that changes conditional rendering -->
<folders v-if="isSearchingInFolders" :key="1234"></folders>
<snippets v-if="!isSearchingInFolders" :key="5678"></snippets>
</div>
</template>
这些组件中的每一个都在本地使用相同的 mixin (searchMixin),如下所示:
<template>
<div>
<div>
<snippet
v-for="item in items"
:snippet="item"
:key="item.id">
</snippet>
<img v-if="busy" src="/icons/loader-grey.svg" width="50">
</div>
<button @click="getItems">Get More</button>
</div>
</template>
<script>
import searchMixin from './mixins/searchMixin';
import Snippet from './snippet';
export default {
components: { Snippet },
mixins: [searchMixin],
data() {
return {
resourceName: 'snippets'
}
},
}
</script>
每个组件在功能上都是等效的,只是标记略有不同,因此出于本示例的目的,文件夹可以替换为片段,反之亦然。
我使用的 mixin 看起来像这样(简化):
import axios from 'axios'
import { EventBus } from '../event-bus';
export default {
data() {
return {
hasMoreItems: true,
busy: false,
items: []
}
},
created() {
EventBus.$on('search', this.getItems)
this.getItems();
},
destroyed() {
this.$store.commit('resetSearchParams')
},
computed: {
endpoint() {
return `/${this.resourceName}/search`
},
busyOrMaximum() {
return this.busy || !this.hasMoreItems;
}
},
methods: {
getItems(reset = false) {
<!-- get the items and add them to this.items -->
}
}
}
在父组件中,当我通过更改 isSearchingInFolders
变量切换渲染时,预期的组件被销毁并从 DOM 中删除(我已经通过从 destroyed()
生命周期挂钩。然而,包含在该组件中的 searchMixin
似乎没有被销毁,并且仍然似乎在监听事件。这意味着当 EventBus.$on('search', this.getItems)
行在更改哪个组件处于活动状态后被触发从父项呈现,this.getItems()
被触发两次。一次用于文件夹,一次用于片段!
我原以为组件的 mixins 会与组件本身一起被销毁。我是否误解了组件销毁的工作原理?
是的,当您传递事件处理程序时,EventBus 会保留对您传递到的函数的引用。这样可以防止破坏组件对象。所以你需要通过调用 EventBus.$off
来清除引用,这样组件才能被销毁。所以你的销毁事件挂钩应该是这样的:
destroyed() {
this.$store.commit('resetSearchParams')
EventBus.$off('search', this.getItems)
},
我有一个有条件地呈现两个子组件之一的父组件:
<template>
<div>
<!-- other code that changes conditional rendering -->
<folders v-if="isSearchingInFolders" :key="1234"></folders>
<snippets v-if="!isSearchingInFolders" :key="5678"></snippets>
</div>
</template>
这些组件中的每一个都在本地使用相同的 mixin (searchMixin),如下所示:
<template>
<div>
<div>
<snippet
v-for="item in items"
:snippet="item"
:key="item.id">
</snippet>
<img v-if="busy" src="/icons/loader-grey.svg" width="50">
</div>
<button @click="getItems">Get More</button>
</div>
</template>
<script>
import searchMixin from './mixins/searchMixin';
import Snippet from './snippet';
export default {
components: { Snippet },
mixins: [searchMixin],
data() {
return {
resourceName: 'snippets'
}
},
}
</script>
每个组件在功能上都是等效的,只是标记略有不同,因此出于本示例的目的,文件夹可以替换为片段,反之亦然。
我使用的 mixin 看起来像这样(简化):
import axios from 'axios'
import { EventBus } from '../event-bus';
export default {
data() {
return {
hasMoreItems: true,
busy: false,
items: []
}
},
created() {
EventBus.$on('search', this.getItems)
this.getItems();
},
destroyed() {
this.$store.commit('resetSearchParams')
},
computed: {
endpoint() {
return `/${this.resourceName}/search`
},
busyOrMaximum() {
return this.busy || !this.hasMoreItems;
}
},
methods: {
getItems(reset = false) {
<!-- get the items and add them to this.items -->
}
}
}
在父组件中,当我通过更改 isSearchingInFolders
变量切换渲染时,预期的组件被销毁并从 DOM 中删除(我已经通过从 destroyed()
生命周期挂钩。然而,包含在该组件中的 searchMixin
似乎没有被销毁,并且仍然似乎在监听事件。这意味着当 EventBus.$on('search', this.getItems)
行在更改哪个组件处于活动状态后被触发从父项呈现,this.getItems()
被触发两次。一次用于文件夹,一次用于片段!
我原以为组件的 mixins 会与组件本身一起被销毁。我是否误解了组件销毁的工作原理?
是的,当您传递事件处理程序时,EventBus 会保留对您传递到的函数的引用。这样可以防止破坏组件对象。所以你需要通过调用 EventBus.$off
来清除引用,这样组件才能被销毁。所以你的销毁事件挂钩应该是这样的:
destroyed() {
this.$store.commit('resetSearchParams')
EventBus.$off('search', this.getItems)
},