Vue 项目中父子传值使用Vuex异步数据不更新问题
一.背景
在Vue项目开发中,我们经常需要在父组件中定义一个fields配置数组,然后将它传递给子组件,子组件根据fiedls渲染筛选表单
比如: 我本来是想直接用vuex state里面的数据直接传过去的
//父组件
<SimpleFilterBar :fields="fields" :model="form" />//js部分 data () {return {fields: [{label: '运营区',prop: 'regionid',type: 'select',options: this.$store.state.regionList // Vuex 异步数据}]}
},
created(){this.$store.dispatch('Publicdata/fetchRegionList')
}
问题来了,Vuex异步获取的regionList更新后,fields[0].options并不会自动更新,子组件也收不到最新数据,一直是空数组,也就是Vuex里面初始化的数据
二.原因分析
Vue的响应式机制确实能追踪对象/数组的变化,但这里有一个 "初始化引用" 问题 :
- 当父组件执行data( ) 时, this.$store.state.regionList 还是一个空数组 [ ];
- fields [0].options 就固定成了当时的那个空数组的引用;
- 后续Vuex 更新regionList时,fields[0].options 并没有重新绑定,而是仍然向老的引用;
- 所以,子组件里的fields 也不会随着Vuex 更新而变化
换句话说: 响应式只会跟踪属性的变化,但不会帮你"替换引用"
三. 解决方案
方案一: 使用计算属性(推荐)
直接把fields写成计算属性,而不是写死在data里
computed: {...mapState('Publicdata', ['regionList']),fields() {return [{label: '运营区',prop: 'regionid',type: 'select',options: this.regionList}]}
}
- 优点 : regionList 更新后, fields 会自动重新计算,子组件拿到的就是最新数据
- 缺点: 每次依赖变化都会诚信生成fiedls,但这点性能开销几乎可以忽略
方案二: watch 赋值
保留 fields 在 data 里,但监听Vuex数据变化,手动更新fields :
data() {return {fields: [{ label: '运营区', prop: 'regionid', type: 'select', options: [] }]}
},
watch: {regionList(newVal) {this.fields[0].options = newVal}
},
computed: {...mapState('Publicdata', ['regionList'])
}
- 优点: 对已有写法改动小;
- 缺点: 需要写watch,稍显繁琐
四. 总结
- 问题本质: 在data( ) 里引用Vuex异步数据时,引用在初始化就固定了,不会随着Vuex后续更新自动刷新
- 推荐方案: 把fileds定义成计算属性,依赖Vuex state; 这样数据更新-> fields更新->子组件也更新