如何向嵌套数组的cards数组添加对象?遇对象不可扩展错误
解决Apollo Cache中“对象不可扩展”错误:向嵌套数组添加元素
问题场景
从GraphQL获取嵌套结构数据后,尝试向id为1的list项的cards数组添加新对象时,触发“对象不可扩展”错误。
数据示例
{ "data": { "board": { "id": "1", "title": "Grocieries", "color": "teal", "lists": [ { "id": "1", "title": "To-Do", "cards": [ { "id": "1", "title": "Write novel" }, { "id": "2", "title": "Buy food" }, { "id": "3", "title": "Paint a picture" } ] }, { "id": "2", "title": "In progress", "cards": [ { "id": "4", "title": "Buy groceries" }, { "id": "5", "title": "Pay the bills" } ] }, { "id": "3", "title": "Done", "cards": [ { "id": "8", "title": "Get the car fixed" }, { "id": "9", "title": "Write novel" } ] } ] } } }
报错代码
<script> import CardAdd from '../graphql/mutations/CardAdd'; import BoardQuery from '../graphql/queries/BoardWithListsAndCards'; export default { methods: { cardAdd(){ this.$apollo.mutate({ mutation: CardAdd, variables: { title: "Mutation added", order: 1, listId: 1, ownerId: 1 }, update(store, { data: { cardAdd } }){ let data = store.readQuery({ query: BoardQuery, variables: { id: 1 } }); // 直接修改冻结对象触发错误 data.board.lists.find(list => list.id == 1).cards.push(cardAdd); } }); } } } </script>
问题原因
Apollo Client返回的查询结果是不可变(冻结)对象,目的是防止意外修改缓存数据导致状态不一致。直接修改这些对象会触发“对象不可扩展”的错误。
解决方案
创建数据的深拷贝,修改拷贝后的对象,再通过store.writeQuery将更新后的数据写回缓存。
修改后的代码
<script> import CardAdd from '../graphql/mutations/CardAdd'; import BoardQuery from '../graphql/queries/BoardWithListsAndCards'; export default { methods: { cardAdd(){ this.$apollo.mutate({ mutation: CardAdd, variables: { title: "Mutation added", order: 1, listId: 1, ownerId: 1 }, update(store, { data: { cardAdd } }){ // 1. 读取原始缓存数据 const originalData = store.readQuery({ query: BoardQuery, variables: { id: 1 } }); // 2. 深拷贝数据(避免直接修改冻结对象) const updatedData = JSON.parse(JSON.stringify(originalData)); // 3. 找到目标list并添加新card(注意id类型匹配,原始数据为字符串) const targetList = updatedData.board.lists.find(list => list.id === "1"); if (targetList) { targetList.cards.push(cardAdd); } // 4. 将修改后的数据写回缓存 store.writeQuery({ query: BoardQuery, variables: { id: 1 }, data: updatedData }); } }); } } } </script>
额外说明
JSON.parse(JSON.stringify())是通用的深拷贝方式,如果数据包含函数、Symbol等特殊类型,建议使用lodash.cloneDeep这类专业工具。- 必须调用
writeQuery将修改后的数据写回缓存,否则界面不会同步更新。 - 使用
===严格相等判断id,避免类型不匹配导致找不到目标list。
内容的提问来源于stack exchange,提问作者Halit
相关产品推荐
相关产品推荐

