我正在为 Angular 2 应用程序使用 @ngrx/store。
我的商店拥有一个列表,比如 Book
对象。我想更新其中一个对象中的字段。我也碰巧有一个要更新的 Book 实例的 Observable(比如,selectedBook
)。
为了进行更新,我打算使用 UpdateBookAction
和新书的有效负载调用 reducer。因此,我通过订阅 selectedBook
然后调用 Object.assign() 对现有 Book 对象进行了深度复制。
但是当我尝试写入副本的其中一个字段时,出现以下错误。 (这恰好与我尝试直接写入商店中的 Book 对象时遇到的错误相同。)
错误
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);
}
但我们不只是在这里谈论两个领域……如果我的书有多个领域怎么办?我是否必须每次都从头开始手动构建一本新书来更新一个字段?
我的解决方案是使用 Object.assign({}, book)
进行深度复制(而不是改变旧的!),然后仅更新我正在查找的字段触摸。
最佳答案
ngrx store 的想法是只有一个真实的地方,这意味着所有对象都是不可变的,改变任何东西的唯一方法是将所有东西作为一个整体重新创建。此外,您可能正在使用 ngrx freeze ( https://github.com/codewareio/ngrx-store-freeze ),这意味着所有对象都将以只读方式创建,因此您将无法更改任何对象(如果您想完全遵循 redux 模式,这有利于开发).如果您删除商店卡住对象的部分,您将能够更改它,但这不是最佳实践。
我建议您执行以下操作:使用带异步管道的 ngrx observable 将数据(在您的案例书中)放入只能获取输入和输出某些事件的dumb组件中。然后,在dumb组件内部,您可以通过复制该对象来“编辑”该对象,完成后,您可以将更改发回订阅商店的智能组件,并允许它更改状态通过商店(提交)。这种方式是最好的,因为为了一个非常小的变化而改变整个状态并不是很常见(比如双向绑定(bind),当用户输入时......)。
如果您遵循 redux 模式,那么您将能够添加历史记录,这意味着商店将保留最近 X 状态重新创建的副本,因此您可以获得撤消功能、更易于调试、时间线等
您的问题是您直接编辑属性而不是重新创建整个状态。
关于javascript - 更新 ngrx/store 中的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40899859/