Vue子组件复用后Vuex Getter数据失去响应的问题排查
嗨,我来帮你捋捋这个问题——你把原本在页面里正常工作的查询banner抽成独立组件后,Vuex getter的变化就不再触发组件更新了,对吧?我碰到过类似的情况,大概率是这几个原因导致的,咱们逐个排查:
1. 检查store模块引用是否出错
你在编辑里写的是multiTagsStore,但最初的代码里是queryStore,会不会是抽组件的时候不小心把store模块名写错了?比如原本的getter在queryStore模块下,结果组件里写成了multiTagsStore,那自然拿不到正确的状态,也就不会跟着变化了。
一定要确认组件里mapGetters的模块名和store定义的模块名完全一致(包括大小写,Vuex模块名是大小写敏感的哦)。比如正确的应该是:
computed: { ...mapGetters("queryStore", ['getQueryParams']), }
2. 状态修改是否遵循Vue响应式规则
虽然你在Vue DevTools里看到store变了,但如果修改state.queryParams的时候没按Vue的响应式方式来,组件是感知不到变化的。比如这些错误写法:
// 直接给对象加属性,不会触发响应式 state.queryParams.newParam = 'test' // 直接删除属性,也不会触发 delete state.queryParams.oldParam
正确的做法应该用Vue提供的方法或者替换整个对象引用:
// 添加属性用Vue.set Vue.set(state.queryParams, 'newParam', 'test') // 删除属性用Vue.delete Vue.delete(state.queryParams, 'oldParam') // 替换整个对象(确保生成新的引用) state.queryParams = { ...state.queryParams, newParam: 'test' }
Vue的响应式系统依赖属性劫持,只有通过这些方式修改,才能让组件感知到状态变化。
3. 组件的监听方式是否合理
你尝试用watch监听queryStore,但默认watch是浅监听,如果只是对象内部属性变化,不会触发回调。可以改成深度监听,同时加上immediate: true让组件初始化时就执行一次:
watch: { queryStore: { handler(val) { this.showBanner = Object.keys(val).length > 0 }, deep: true, // 开启深度监听对象内部属性 immediate: true // 组件加载时立即执行一次 } }
不过更推荐用computed直接计算showBanner,这更符合Vue的响应式设计思路,代码也更简洁:
computed: { ...mapGetters("queryStore", ['getQueryParams']), showBanner() { return Object.keys(this.getQueryParams).length > 0 } }
然后模板里直接用v-if="showBanner"就行,只要getQueryParams的状态变化符合响应式规则,computed会自动更新。
4. 组件是否被缓存了
会不会你的QueryBanner组件被包裹在<keep-alive>标签里了?缓存后的组件第一次渲染后不会重新执行生命周期,普通的状态变化可能无法触发更新。
如果确实用了<keep-alive>,要么去掉缓存,要么在activated钩子里手动同步状态,或者用上面提到的带immediate: true的watch。
5. Getter是否返回了非响应式对象
检查下你的getter有没有做特殊处理,比如把状态转成了非响应式的对象:
// 错误示例:返回了一个非响应式的新对象 getQueryParams(state) { return JSON.parse(JSON.stringify(state.queryParams)) }
这种情况每次返回的都是新对象,但如果状态修改没有触发响应式,getter也不会更新。不过看你原来的getter是直接返回state.queryParams,这个可能性不大,但可以排查下。
按照上面的步骤一个个检查,应该能找到问题所在~
备注:内容来源于stack exchange,提问作者knirirr

