更新 ngrx/store 中的对象 [英] Updating an object in the ngrx/store

查看:21
本文介绍了更新 ngrx/store 中的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将 @ngrx/store 用于 Angular 2 应用程序.

I'm using @ngrx/store for an Angular 2 app.

我的商店有一个列表,比如 Book 对象.我想更新这些对象之一中的字段.我也碰巧有一个我想要更新的 Book 实例的 Observable(比如,selectedBook).

My store holds a list of say, Book objects. I want to update a field in one of those objects. I also happen to have an Observable of the Book instance I'm looking to update (say, selectedBook).

为了进行更新,我打算使用 UpdateBookAction 和新书的有效负载调用减速器.因此,我通过订阅 selectedBook 然后调用 Object.assign() 来制作现有 Book 对象的深层副本.

To do the update I intend on calling the reducer with an UpdateBookAction, and a payload of the new Book. So I make a deep copy of the existing Book object by subscribing to selectedBook and then calling Object.assign().

但是当我尝试写入副本的其中一个字段时,出现以下错误.(如果我尝试直接写入商店中的 Book 对象,这恰好与我得到的错误相同.)

But when I try to write to one of the fields of the copy I get the following error. (It happens to be the same error I get if I were to try to write directly to the Book object in the store.)

错误

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);

    }
}

评论后的澄清

我假设我可以使用不是商店的整个状态的有效负载进行操作.(事实上​​,这似乎是必要的,不是吗?)鉴于文档,我相信情况确实如此.

I was under the assumption that I could have an action with a payload that was not the entire state of the store. (In fact that seems necessary, no?) I'm confident that this is the case given the documentation.

我希望采取的行动是这样的:

The action I'm looking to take is something like this:

Action = UPDATE, payload = {'id': 1234, 'name': 'something new'}

如前所述,我打算像这样拨打电话:

As mentioned, I intend on making that call like this:

this.store.dispatch(action);

大概在幕后,ngrx 正在将我的操作与(不可变的)当前状态一起传递给减速器.

Presumably under the hood, ngrx is passing my action to the reducer along with the (immutable) current state.

所以从那里开始,一切都应该正常.我在 reducer 中的逻辑不会改变现有状态,它只是根据现有状态和我传入的有效负载创建一个新状态.

So from there, everything should work okay. My logic inside the reducer doesn't mutate the existing state, it simply creates a new one out of the existing state and the payload I've passed in.

这里真正的问题是我如何合理地构建新的objectToUpdate",以便我可以将其作为有效负载传入.

The real question here is how I can reasonably build the new "objectToUpdate" such that I can pass that in as the payload.

我可以这样做:

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);

}

但我们在这里讨论的不仅仅是两个领域……如果我的书有多个领域怎么办?每次更新一个字段时,我是否都必须从头开始手动构建一本新书?

But we're not just talking about two fields here... what if my book has several fields? Do I have to manually build from scratch a new Book each time just to update one field?

我的解决方案是使用 Object.assign({}, book) 进行深度复制(而不是改变旧的!)然后只更新我想要的领域触摸.

My solution was to do a deep copy using Object.assign({}, book) (and not mutate the old one!) and subsequently make the update to solely the field I was looking to touch.

推荐答案

ngrx store 的想法是拥有一个且只有一个真理的地方,这意味着所有的对象都是不可变的,并且是改变任何事物的唯一方法是将一切重新创造为一个整体.此外,您可能正在使用 ngrx 冻结(https://github.com/codewareio/ngrx-store-freeze) 这意味着所有对象都将被创建为只读,因此您将无法更改任何对象(如果您想完全遵循 redux 模式,这对开发很有好处).如果您删除商店冻结对象的部分,您将能够更改它,但这不是最佳实践.

The idea of the ngrx store is to have one and only one single place of truth, which means all the objects are immutable, and the only way to change anything is to recreate everything as a whole. Also, you are probably using the ngrx freeze (https://github.com/codewareio/ngrx-store-freeze) which means that all of the objects will be created read-only so you wont be able to change any (This is good for development if you want to completely follow the redux pattern). If you remove the part where the store freezes the object, you will be able to change it, but thats not best practice.

我建议您如下:使用带有异步管道的 ngrx observable 将数据(在您的案例书中)放入一个只能获取输入和输出某些事件的哑组件中.然后,在哑组件内部,您可以通过复制该对象来编辑"该对象,完成后,您可以将更改发送回订阅商店的智能组件并允许它更改状态通过商店(提交).这种方式是最好的,因为对于非常小的更改(例如双向绑定,当用户键入..)时更改整个状态并不常见.

What I would suggest you is the following: Use the ngrx observable with async pipe to put the data (in your case books) in a dumb component which can only get input and output some event. Than, inside of the dumb component you can "edit" that object by making a copy of it, and after you are done, you can emit back the changes to the smart component which is subscribed to the store and allow it to change the state via the store (commit). This way is best because it is not very common to change the whole state for a really small change (like two way binding, when user types..).

如果您遵循 redux 模式,那么您将能够添加历史记录,这意味着商店将保留最后 X 状态重新创建的副本,因此您可以获得 UNDO 功能、更易于调试、时间轴等

If you follow the redux pattern, than you will be able to add history, which means the store will keep a copies of the last X state recreations, so you can get UNDO functionality, easier to debug, timeline etc

您的问题是您正在直接编辑属性,而不是重新创建整个状态.

Your problem is that you are directly editing the property instead of recreating the whole state.

这篇关于更新 ngrx/store 中的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆