我的商店拥有一个说明书,Book对象的列表.我想更新其中一个对象中的字段.我也碰巧有一个我想要更新的Book实例的Observable(比如,selectedBook).
为了进行更新,我打算使用UpdateBookAction调用reducer,以及新Book的有效负载.所以我通过订阅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中的逻辑不会改变现有状态,它只是从现有状态和我传入的有效负载中创建一个新状态.
这里真正的问题是如何合理地构建新的“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 observable将数据(在您的案例中)放入一个只能输入和输出某个事件的哑组件中.在哑组件内部,您可以通过复制它来“编辑”该对象,并在完成后,您可以将更改发回到订阅商店的智能组件并允许其更改状态通过商店(提交).这种方式是最好的,因为对于一个非常小的更改来改变整个状态并不常见(比如双向绑定,当用户输入时……).
如果您遵循redux模式,那么您将能够添加历史记录,这意味着商店将保留最后X个状态重新创建的副本,因此您可以获得UNDO功能,更易于调试,时间线等
您的问题是您正在直接编辑属性而不是重新创建整个状态.