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
相关产品推荐
相关产品推荐

