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

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

问题描述

我在Angular 2应用中使用@ ngrx/store.

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和新Book的有效负载调用reducer.因此,我通过订阅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存储的想法是只有一个真实的地方,这意味着所有对象都是不可变的,并且是改变任何事物的唯一方法是重新创建整体.另外,您可能正在使用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天全站免登陆