Angular报错:object is not extensible,向*ngFor绑定数组添加元素失败
解决TypeError: Cannot add property X, object is not extensible问题
这个错误通常有两个核心原因,咱们一步步拆解解决:
1. 数组未初始化导致的基础问题
你只声明了webdesign数组的类型,但没有给它初始值,默认它是undefined。虽然你的错误提示看起来是对象不可扩展,但如果没初始化,第一次调用push时其实会先触发Cannot read property 'push' of undefined,可能是后续操作叠加了问题。
先修正数组的声明,给它一个初始空数组:
public webdesign: Array<WebDesign> = [];
2. Apollo Client返回的对象被冻结
Apollo Client默认启用了freezeResults选项(默认值为true),它会冻结所有从服务端返回的数据对象,目的是防止意外修改缓存数据。这些冻结的对象是不可扩展、不可修改的,当你尝试把它们直接加入数组(或者后续修改它们)时,就会触发object is not extensible错误。
解决这个问题的方法是把返回的对象克隆成普通的可扩展对象,有几种方式:
方法一:使用扩展运算符浅克隆
this.apollo.query(`{ getWebDesignList (page : ${this.page++}) { _id title description screenPath profilPictureCreator creatorName websiteLink createdAt } }`).subscribe(r => { const webDesignItems = r.data.getWebDesignList.map(item => ({ ...item })); this.webdesign.push(...webDesignItems); });
方法二:使用Object.assign克隆
this.apollo.query(`{ getWebDesignList (page : ${this.page++}) { _id title description screenPath profilPictureCreator creatorName websiteLink createdAt } }`).subscribe(r => { const webDesignItems = r.data.getWebDesignList.map(item => Object.assign({}, item)); this.webdesign.push(...webDesignItems); });
方法三:全局关闭Apollo的冻结(不推荐)
如果你确定不需要缓存数据的冻结保护,可以在Apollo Client初始化时关闭freezeResults:
const apolloClient = new ApolloClient({ // 其他配置... cache: new InMemoryCache(), freezeResults: false // 关闭冻结 });
不过这个方法不推荐,因为冻结是Apollo保护缓存一致性的重要机制,关闭后可能导致意外的缓存修改问题。
额外优化:使用RxJS的操作符简化代码
你可以用RxJS的map操作符在订阅前就处理好数据,让代码更整洁:
loadMore(): void { this.apollo.query({ query: gql`{ getWebDesignList (page : ${this.page++}) { _id title description screenPath profilPictureCreator creatorName websiteLink createdAt } }` }).pipe( map(r => r.data.getWebDesignList.map(item => ({ ...item }))) ).subscribe(webDesignItems => { this.webdesign.push(...webDesignItems); }); }
另外,建议使用gql标签来包裹GraphQL查询,这是Apollo推荐的写法,能获得语法高亮和类型检查的支持。
内容的提问来源于stack exchange,提问作者Thomas Dupont
相关产品推荐
相关产品推荐

