Vue点击兄弟组件筛选按钮触发fetch更新后重绘子组件的问题
Vue兄弟组件点击筛选按钮重复触发列表刷新解决方案
问题根因
当前watch仅触发一次的核心原因是:父组件的keywords变量只有在传入的新关键词为真值且和旧值不同时才会更新,Vue的watch默认仅在监听的属性值发生变化时才会触发回调,若两次点击筛选按钮传入的关键词一致,filters属性没有变化,就不会触发拉取逻辑。
可选解决方案
方案1:新增刷新触发标识(推荐,兼容关键词不变也需要刷新的需求)
父组件代码修改
<template> <div class="container"> <Filter @changedKeywords="reloadItems"></Filter> <!-- 新增refreshTag属性传给List组件 --> <List :platforms="platforms" :filters="keywords" :refresh-tag="refreshTag"></List> </div> </template> <script> // 原有import逻辑保留 export default { name: "Holder", components: {Filter, List}, methods: { reloadItems: function (data){ if(data.keywords) {this.keywords = data.keywords}; // 每次触发筛选事件都更新refreshTag,保证值一定变化 this.refreshTag = Date.now(); } }, data(){ return { keywords : null, refreshTag: 0 // 新增刷新标识变量 } } } </script>
List组件代码修改
<script> import Game from "./Game"; export default { name: "List", props: ['filters', 'platforms', 'refreshTag'], // 新增props接收刷新标识 components: {Game}, data() { return{ list: [], } }, watch: { // 监听refreshTag的变化,每次变化都触发拉取逻辑 refreshTag: { async handler() { console.log('每次点击都会触发'); const res = await fetch('/api/game/list/9', { method: 'POST', body: JSON.stringify({'filters' : this.filters}) }); this.list = await res.json(); }, immediate: true // 首次加载时自动触发一次 } }, } </script>
方案2:使用key强制重建组件(简单粗暴,适合小型列表场景)
直接给List组件绑定动态key,每次触发筛选就更新key,Vue会销毁旧的List组件实例,新建全新的实例,自动重新触发数据拉取逻辑:
<template> <div class="container"> <Filter @changedKeywords="reloadItems"></Filter> <!-- 绑定动态key --> <List :platforms="platforms" :filters="keywords" :key="listKey"></List> </div> </template> <script> // 原有import逻辑保留 export default { name: "Holder", components: {Filter, List}, methods: { reloadItems: function (data){ if(data.keywords) {this.keywords = data.keywords}; this.listKey = Date.now(); } }, data(){ return { keywords : null, listKey: 0 } } } </script>
该方案不需要修改List组件代码,如果要首次加载自动拉取,给原有filters的watch加immediate: true即可。
方案3:修复现有逻辑(仅当关键词变化才需要刷新时使用)
如果业务逻辑确实只需要关键词变化时才刷新,先检查Filter组件changedKeywords事件的传值,确认每次点击筛选按钮都会传正确的data.keywords,同时确认两次传入的关键词不会完全一致。如果filters是引用类型(比如对象、数组),可以给watch加deep: true配置,监听内部属性的变化:
watch: { filters: { async handler() { // 原有拉取逻辑保留 }, deep: true, immediate: true } }
内容的提问来源于stack exchange,提问作者Efkiss
相关产品推荐
相关产品推荐

