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

从Pinia通过storeToRefs传Props时响应式失效及删除行异常问题

问题解决:删除发票行时页面显示异常

问题现象

用Pinia管理invoiceLines数组时,删除指定行后,控制台和Store里的数据已正确移除对应productId的行,但页面上消失的却是最后一行,选中的目标行仍保留在界面上。

核心原因

列表渲染时用数组index作为:key,导致Vue组件复用逻辑出错。Vue依赖key判断列表项的唯一性,用索引当key的话,删除中间元素后,剩余元素的索引会重新排列,Vue会复用之前的组件实例,造成UI渲染和实际数据不匹配。

解决方案步骤

1. 给新增空白行生成唯一ID

修改Pinia Store的addInvoiceLine方法,确保每一行的productId唯一,避免重复冲突:

// Pinia store
import { defineStore } from 'pinia'

export const useInvoiceStore = defineStore('InvoiceStore', {
  state: () => ({
    invoiceLines: [],
  }),
  actions: {
    // 添加发票行
    addInvoiceLine(newLine) {
      // 用时间戳生成唯一productId
      const uniqueId = Date.now();
      this.invoiceLines.push({...newLine, productId: uniqueId});
    },

    // 更新发票行
    updateInvoiceLine(oldProductId, newLine) {
      this.invoiceLines = this.invoiceLines.map( line => {
        if (line.productId === oldProductId) {
          return newLine
        }
        return line
      })
    },

    // 删除发票行
    removeInvoiceLine(productId) {
      this.invoiceLines = this.invoiceLines.filter(obj => obj.productId !== productId)
    },
  },
})

2. 把列表渲染的Key改为唯一标识

在InvoiceLine.vue中,将v-for的:key从index替换为line.productId:

<!-- InvoiceLine.vue 模板部分 -->
<VCardText>
  <div
    v-for="(line) in invoiceLines"
    :key="line.productId"
    class="my-4 ma-sm-4"
  >
    <InvoiceLineEdit
      :data="line"
      @remove-line="removeLineItem"
      @update-line="updateLineItem"
    />
  </div>
  <div class="mt-4 ma-sm-4">
    <VBtn @click="addLineItem">
      添加行项目
    </VBtn>
  </div>
</VCardText>

同时可删除模板和子组件中无用的index参数。

3. 修复更新行时的参数错误

在InvoiceLineEdit.vue的watch(totalPrice)回调中,之前错误传递props.index作为更新标识,改为传递当前行的productId:

// InvoiceLineEdit.vue 中的watch回调
watch(totalPrice, () => {
  if(lineItem.value) {
    console.log('Total update', lineItem.value)

    const result =  totalPrice.value * 0.15 
    
    totalIncludVAT.value = Number(totalPrice.value) + Number(result) 
    lineItem.value.vat = result
    lineItem.value.total = totalPrice.value
    // 传递lineItem的productId而非index
    emit('updateLine', lineItem.value.productId, lineItem.value)
  }
}, { immediate: true })

4. 调整空白行模板

去掉BLANK_ITEM_BASE中的固定productId,由Store生成唯一值:

// InvoiceLine.vue 中的空白行模板
const BLANK_ITEM_BASE =  {
  description: '',
  unitPrice: 0,
  quantity: 1,
  discount: 0,
  vat: 0,
}

验证修改

完成上述调整后,删除指定行时,Vue会通过唯一的productId正确识别要销毁的组件实例,页面显示将与Store中的数据保持一致。

内容的提问来源于stack exchange,提问作者A. Student

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 01:37:09