在 Vue3 组合式 API 开发过程中,组件间数据传递的响应性问题是开发者常遇到的 “坑”。本文将通过一个实际项目案例,深入分析 computed 计算属性在处理深层数据时的响应性失效问题,并提供经过实践验证的解决方案。
问题场景再现
在 H5 项目开发中,由于 Vue3 路由跳转通过{name: '', params: {}}形式传递参数存在限制,笔者采用 Pinia 存储方式进行组件间数据传递。在接收数据的组件中,最初采用了如下实现方式:
import { useParamsStore } from '@/stores/legalReview'
const { getParams } = useParamsStore()
const systemPattData = computed(() => {
const data = JSON.parse(getParams().result)
return [...data]
})
这段代码看似合理,通过 computed 计算属性从 Pinia 仓库中获取数据并解析处理。但在实际操作中发现,当页面采用嵌套形式展示数据并控制展开 / 关闭状态时,点击操作虽然改变了数据,页面却无法及时更新。即使尝试使用 watch 监听、nextTick 等方法也未能解决问题。
computed 计算属性的特性分析
要理解问题根源,首先需要明确 computed 计算属性的核心特性:
在上述案例中,getParams().result经过 JSON.parse 转换后得到的是一个普通 JavaScript 对象,而非 Vue 的响应式对象。将其转换为数组返回后,虽然表面上是响应式的,但当数组内部的深层数据发生变化时,computed 无法追踪到这些变化,因为它的缓存机制会认为原始依赖没有改变。
解决方案:使用响应式变量
解决这个问题的关键在于确保数据从一开始就是响应式的。经过多次尝试,发现通过 ref 定义响应式变量,并在 onMounted 中进行赋值的方式可以完美解决:
import { ref, onMounted } from 'vue'
import { useParamsStore } from '@/stores/legalReview'
const { getParams } = useParamsStore()
const systemPattData = ref([]) // 定义响应式变量
onMounted(() => {
// 在挂载时解析数据并赋值
const data = JSON.parse(getParams().result)
systemPattData.value = [...data]
})
这种方式的核心优势在于:
需要特别注意的是,在 Vue3 中,响应式系统的实现基于 Proxy,无论是 reactive 还是 ref 创建的响应式对象,都需要遵循其响应式规则:
总结与注意事项
通过这个问题的排查与解决,我们可以得出以下经验:
希望本文能帮助大家在 Vue3 开发中避开类似的响应性问题,提高开发效率。如果有其他解决方案或疑问,欢迎在评论区交流讨论!