我正在为一个 Angular 2 应用程序使用 @ngrx/store。
我的 store 包含一系列的 Book 对象。我希望更新其中一个对象的字段。假设我有一个 Book 实例的 Observable,我想要进行更新操作(比如 selectedBook)。
为了进行更新,我打算使用一个 UpdateBookAction、以及新 Book 对象作为负载来调用 reducer。因此,我通过订阅 selectedBook 并调用 Object.assign() 来深度复制现有的 Book 对象。
但是当我尝试写入副本中的某个字段时,会出现以下错误(如果我尝试直接写入 store 中的 Book 对象,则会出现相同的错误)。
Error
Cannot assign to read only property 'name' of object '#<Object>' at ViewWrappedError.BaseError [as constructor]
代码
ngOnInit() {
this.book$ = this.store.let(fromRoot.getSelectedBook);
//...
}
someFunction() {
//...
this.book$.subscribe(book => {
let updatedBook = Object.assign({}, book);
updatedBook.name = 'something else'; // <--- THIS IS WHAT THROWS
let action = new BookUpdateAction(updatedBook);
this.store.dispatch(action);
}
}
评论后的澄清
我曾认为我可以有一个带有有效载荷的操作,但它不必是整个商店的状态。(事实上,这似乎是必要的,不是吗?)我相信这是根据文档说明的情况。
我想要执行的操作类似于:
Action = UPDATE, payload = {'id': 1234, 'name': 'something new'}
如前所述,我打算这样做决定:
this.store.dispatch(action);
可以假设 ngrx 在幕后将我的操作与(不可变的)当前状态一起传递给了 reducer。从那里开始,一切都应该正常工作。我在 reducer 内部的逻辑不会改变现有状态,而是基于现有状态和我传递的有效负载创建一个新的状态。
真正的问题在于如何合理地构建新的“objectToUpdate”,以便我可以将其作为有效负载传递进去。
我可以像这样做:
this.book$.subscribe(book => {
let updatedBook = new Book();
updatedBook.id = book.id;
//set all other fields manually...
updatedBook.name = 'something else';
let action = new BookUpdateAction(updatedBook);
this.store.dispatch(action);
}
但我们在这里不仅仅是谈论两个字段... 如果我的书有多个字段怎么办?我需要每次手动从头开始构建一个新的Book来更新一个字段吗?
我的解决方案是使用 Object.assign({}, book)
进行深度复制(而不是改变旧值!)并随后仅对我想要修改的字段进行更新。
Object.assign({}, book, { name: 'something else' })
? - rob3c