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

Pinia中increaseUpvote方法意外修改mockBooks原数据问题求助

问题分析:increaseUpvote方法意外修改mockBooks的原因及解决办法

问题场景

我编写了如下测试代码:

it('increaseUpvote Should increase Upvote of selected book', () => {
    const store = useBooksStore()
    store.$patch({ books: mockBooks })
    expect(store.books[0].upvotes).toBe(1111)
    store.increaseUpvote(mockBooks[0].slug)
    expect(store.books[0].upvotes).toBe(1112)
})

测试发现increaseUpvote方法虽实现了预期功能,但它不仅修改了state.books中的数据,还意外改变了mockBooks的数值。原本预期以下测试代码能正常运行,但实际失败:

it('increaseUpvote Should increase Upvote of selected book', () => {
    const store = useBooksStore()
    store.$patch({ books: mockBooks })
    expect(store.books[0].upvotes).toBe(mockBooks[0].upvotes)
    store.increaseUpvote(mockBooks[0].slug)
    expect(store.books[0].upvotes).toBe(mockBooks[0].upvotes +1)
}) 

我还尝试使用扩展运算符[...mockBooks]复制mockBooks,但mockBooks的upvotes数值仍然会被修改。

原因解析

这是典型的引用类型浅拷贝问题:

  • JavaScript中数组和对象都是引用类型,直接赋值store.$patch({ books: mockBooks })时,store.books和mockBooks指向的是同一个数组内存地址。
  • 用扩展运算符[...mockBooks]复制数组,只是创建了一个新的数组外壳,但数组里的每个book对象还是引用原来的内存地址。
  • 当increaseUpvote方法修改store.books中某个book的upvotes属性时,本质是在操作和mockBooks里同一个对象的引用,所以mockBooks的数据会跟着改变。

解决办法

需要对mockBooks进行深拷贝,确保数组及内部的每个对象都是独立的副本,常用方式有三种:

1. JSON序列化反序列化(简单易用)

store.$patch({ books: JSON.parse(JSON.stringify(mockBooks)) })

注意:这种方式会忽略函数、Symbol、undefined等特殊类型,适合结构简单的数据。

2. 手动遍历拷贝对象(灵活可控)

const deepCopiedBooks = mockBooks.map(book => ({ ...book }))
store.$patch({ books: deepCopiedBooks })

适合对象结构不复杂的场景,可按需修改拷贝的属性。

3. 第三方库深拷贝(可靠全面)

比如用Lodash的cloneDeep:

import cloneDeep from 'lodash/cloneDeep'

const deepCopiedBooks = cloneDeep(mockBooks)
store.$patch({ books: deepCopiedBooks })

能处理各种复杂的引用类型结构,是最稳妥的方式。

修改后的测试代码示例

it('increaseUpvote Should increase Upvote of selected book', () => {
    const store = useBooksStore()
    // 深拷贝mockBooks,避免修改原数据
    const deepCopiedBooks = JSON.parse(JSON.stringify(mockBooks))
    store.$patch({ books: deepCopiedBooks })
    
    expect(store.books[0].upvotes).toBe(mockBooks[0].upvotes)
    store.increaseUpvote(mockBooks[0].slug)
    expect(store.books[0].upvotes).toBe(mockBooks[0].upvotes + 1)
    // 验证原mockBooks未被修改
    expect(mockBooks[0].upvotes).toBe(1111)
}) 

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 20:21:15