Vue 2.6.14页面刷新时组件数据未正常赋值的问题排查
我来帮你拆解这个问题——其实核心差异在于页面刷新和热重载时,父组件传递employees prop的时机完全不同,这才导致了看似矛盾的现象。
先搞懂两种场景的本质区别
1. 热重载时的情况
Vue-cli的热重载是开发环境的特殊特性,它会尽可能保留应用的当前状态:比如父组件之前已经完成了数据加载(比如从API拿到了employees),热重载只会重新编译更新的组件代码,不会重置整个应用的状态。所以当子组件重新触发mounted时,this.employees已经是有真实数据的数组,slice(0)自然能正确复制出一份新数组赋值给sortedEmployees。
2. 页面刷新时的情况
刷新页面时,整个应用会从0开始初始化:父组件的employees大概率是异步获取的(比如通过axios请求后端接口),而子组件的mounted钩子会在组件挂载完成后立即执行——这时候父组件可能还没拿到接口返回的数据,this.employees实际上是空数组(或者初始的默认值)。你执行this.employees.slice(0)复制的自然就是空数组,所以sortedEmployees最终为空。
你可以做个简单验证:在mounted里加一行打印:
mounted() { console.log('mounted时的employees:', this.employees); this.sortedEmployees = this.employees.slice(0); }
刷新页面时你会看到打印的是空数组,而热重载时打印的是有数据的数组——这就能实锤问题所在了。
为什么监听器能解决?
因为监听器是响应式触发的:当父组件异步获取到数据后,employees prop会更新,这时候监听器就会被调用,此时this.employees已经是有值的数组,复制操作自然能成功。
更优雅的解决方案
除了用监听器,还有两种更贴合Vue设计思路的方式:
方案1:使用计算属性(推荐)
如果你的sortedEmployees只是用来做排序展示,完全没必要维护一个data属性,用计算属性更合适——它会自动响应employees的变化,而且不需要手动处理赋值时机:
props: { employees: Array }, computed: { sortedEmployees() { // 先复制原数组(避免修改原prop),再执行排序逻辑 return this.employees.slice(0).sort((a, b) => { // 这里写你的排序规则,比如按姓名排序:return a.name.localeCompare(b.name) }); } }
不管是页面刷新还是热重载,只要employees更新,计算属性就会自动重新计算,完美适配所有场景。
方案2:延迟子组件渲染
如果一定要用data来维护,你可以在父组件里确保employees有值后再渲染子组件:
<!-- 父组件模板 --> <child-component :employees="employees" v-if="employees.length > 0" />
这样子组件的mounted钩子只会在employees已经有数据时才执行,赋值操作自然能拿到正确的数组。
内容的提问来源于stack exchange,提问作者Antônio Quadrado

