You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue子组件获取Pinia/VueFire对象后丢失响应性的问题

Vue子组件通过ID获取Firestore数据丢失响应性问题

问题背景

父组件通过props传递itemId给子组件,子组件调用Pinia store的itemForId(id)从VueFire/Firestore集合中获取数据。但子组件中的数据丢失响应性:外部更新Firestore文档时,Pinia store的集合和父组件数据会更新,子组件的项却不会同步。

若父组件直接把通过itemForId获取的项传给子组件,响应性正常,但此方案无法满足后续编辑需求,因此需要修复子组件的响应性问题。

相关代码

Pinia Store(projectStore.js)

const projectInfo = useDocument(() => doc(db, projectPath))
const { data:projectItems, promise:itemsPromise } = useCollection(() => collection(db, itemsPath))

function itemForId(id) {
  return projectItems.value.find((item) => item.id === id)
}

父组件(MyParent.vue)

<script setup>
import { useProjectStore } from 'stores/projectStore'

const projectStore = useProjectStore()
const { projectInfo, projectItems } = storeToRefs(projectStore)
</script>
<template>
  <div>子组件接收ID(无响应性)</div>
  <template v-for="itemId in projectInfo.itemOrder" :key="itemId">
    <IdChild :itemId="itemId" />
  </template>

  <div>子组件接收直接传递的项(有响应性)</div>
  <template v-for="itemId in projectInfo.itemOrder" :key="itemId">
    <ItemChild :item="projectStore.itemForId(itemId)" />
  </template>

  <div>原始集合数据(有响应性)</div>
  <div>{{ projectItems }}</div>
</template>

无响应性的子组件(IdChild.vue)

<script setup>
import { useProjectStore } from 'stores/projectStore'

const props = defineProps({ itemId: String })

const projectStore = useProjectStore()
const { projectItems } = storeToRefs(projectStore)

// 仅初始化时赋值,后续不会自动更新
const item = ref(projectStore.itemForId(props.itemId))
</script>
<template>
  <div>{{ item.name }}</div> <!-- 无响应性 -->
  
  <!-- 此写法有响应性,但每个属性单独处理不合理 -->
  <div>{{ projectStore.itemForId(itemId).name }}</div>

  <div>原始集合数据(有响应性)</div>
  <div>{{ projectItems }}</div>
</template>

有响应性但无法编辑的子组件(ItemChild.vue)

<script setup>
import { useProjectStore } from 'stores/projectStore'

const props = defineProps({ item: Object })
</script>
<template>
  <div>{{ item.name }}</div> <!-- 有响应性 -->
</template>

解决方案

核心原因

用ref直接赋值的方式只会在组件初始化时执行一次,不会追踪projectItems或itemId的变化,因此当数据源更新时,子组件的item不会同步更新。

修复代码

将子组件中的ref替换为computed,利用计算属性的响应式依赖追踪特性,自动在数据源变化时重新查找对应项:

修改IdChild.vue:

<script setup>
import { useProjectStore } from 'stores/projectStore'
import { computed } from 'vue'

const props = defineProps({ itemId: String })

const projectStore = useProjectStore()

// 计算属性会自动追踪projectItems和itemId的变化
const item = computed(() => projectStore.itemForId(props.itemId))
</script>
<template>
  <div>{{ item.name }}</div> <!-- 现在具备响应性 -->
</template>

编辑功能说明

修复后可以直接编辑item.value的属性(VueFire返回的文档是响应式Proxy对象),示例编辑逻辑:

// 在IdChild.vue中添加编辑方法
function updateItemName(newName) {
  if (item.value) {
    item.value.name = newName
    // 后续可调用store方法同步到Firestore,例如:
    // projectStore.syncItemToFirestore(item.value)
  }
}

而之前的ItemChild无法编辑是因为Vue props是单向数据流,直接修改props对象不符合设计规范,通过子组件内部用computed获取项的方式,更适合后续的编辑操作。

内容的提问来源于stack exchange,提问作者Brad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 13:27:28